【发布时间】:2017-08-13 16:55:58
【问题描述】:
假设有这样的功能:
function a()
{
$entity = $this->getEntity();
$entity->setSomePrivateVar();
$service = $this->getService();
$service->doSomething($entity);
}
我想测试一下
$service->doSomething($entity);
使用正确的 $entity 调用。
$entity 调用 setSomePrivateVar()
在实际的应用程序代码中我做了这样的事情:
获取实体的模拟并测试是否调用了 setSomePrivateVar。
获取 $service 的 mock 并测试是否使用参数 $entity 调用了 doSomething()。
看起来不错。
但问题是 - 如果我重构代码并首先在服务上调用 doSomething(),然后在 $entity 上调用 setSomePrivateVar(),测试仍然通过。
但是这个函数现在是错误的,因为 doSomething 依赖于由 setSomePrivateVar() 设置的 $entity 私有字段。
例如,我将重构为:
function a()
{
$entity = $this->getEntity();
$service = $this->getService();
$service->doSomething($entity);
// this line moved
$entity->setSomePrivateVar();
}
所以看起来 PhpUnit 没有检查 $entity 私有字段。如果它是例如数组,那么 with() 函数会看到传递的数组与预期的不同。
那么我如何测试 doSomething() 以正确的状态获取 $entity (在将实体传递给 doSomething() 之前已在实体上调用 setSomePrivateVar() )?
也许它与 $entity 被嘲笑有关。
更新现实世界的例子
public function setNotifyUsers(AnnualConsolidation $consolidation, $status)
{
$consolidation->setNotifyUsers($status); // if move this method after the flush(), tesst does not fail
$this->entityManager->persist($consolidation);
$this->entityManager->flush();
}
public function testNotifyUsers()
{
$consolidation = $this->getMockBuilder(AnnualConsolidation::class)
->setMethods(['setNotifyUsers'])
->getMock();
$consolidation
->expects($this->once())
->method('setNotifyUsers')
;
$this->entityManager
->expects($this->at(0))
->method('persist')
->with($consolidation)
;
$this->entityManager
->expects($this->at(1))
->method('flush')
;
/** @var AnnualConsolidation $consolidation */
$this->consolidationsService->setNotifyUsers($consolidation, true);
}
我们正在讨论以这种方式测试 setNotifyUsers 方法是否更好。我试图在不访问数据库的情况下进行测试。有人认为这可能需要通过命中数据库进行测试,因为如果在不改变逻辑的情况下重构方法,则可能需要测试来重构。另一方面 - 这种方法不太可能被重构那么多。
但也许还有一种方法可以测试在persist()之后调用flush()而不告诉索引,因为在其他示例中,在persist之前添加一些调用之后可能需要更新索引,因此可能是工作量太大,无法保持测试正常运行。
但是对于这个主题 - 首先我想知道如何使测试失败 - 如果我在 flush() 之后移动 setNotifyUsers。 测试没有失败。而如果我们使用命中数据库进行测试 - 我们会看到 $consolidation 状态没有更新。
有人告诉检查,断言传递给persist方法的内容。我还没有尝试过,但我不确定在模拟 $consolidation 上这是否可行。模拟的 $consolidation 是否像真正的 $consolidation 那样具有某种状态?
【问题讨论】:
-
您能否添加您的测试代码以更好地了解您如何尝试测试。我的猜测是 doSomething 将需要 $entity 中的私有变量?所以在函数“doSomething”中你会调用 $entity->getSomePrivateVar() ?
标签: unit-testing phpunit