【问题标题】:PHPUnit - assert method call order on different mocksPHPUnit - 在不同的模拟上断言方法调用顺序
【发布时间】:2016-09-29 20:50:14
【问题描述】:

我想测试一个方法,它只调用我的实体对象的方法并将其持久化到数据库中。

public function setNameAndPersistObject($entityObject) {
    $entityObject->setName("John");
    $this->entityManager->persist($entityObject);
}

$entityObject 和 $entityManager 都是模拟对象,而不是实际对象。

我想测试被调用方法的调用顺序,以测试'persist'在'setName'之后被调用,因此新名称“John”被保存在数据库中。我将如何在 PHPUnit 中做到这一点?

【问题讨论】:

  • 我想你会想要使用虚拟数据,而不是真正持久化它,或者连接到坦克或任何东西中。使用平面文件,使用测试调用您的虚拟数据,然后验证它是否可以加载或解析该数据。哦,你要坚持,哎哟。嗯,到一个平面文件?在数据库中连接听起来是个坏主意。
  • 嗯,我认为一种方法可能是我可以模拟persist方法,并将returnCallback设置为克隆传递的实体对象,最后将其与修改后的进行比较。也许有更优雅的方式?
  • 好吧,记住你没有从你的数据库中验证你的数据,所以你需要弄清楚如何模拟它们。如果您想使用实际数据进行测试,请使用虚拟数据。如果您想传递一个对象,我仍然会在平面文件上使用虚拟数据,并使其在与您的测试相同的目录中可用。所以你可以将它与那个平面文件进行比较:-) 在事后看来,我想你可以在你的测试中得到幻想,利用 mysql 的 tmp 表在一次运行中插入和比较测试虚拟数据,我猜等等。;- ) 但这太花哨了。
  • 从这个案例中抽象出来,前提是“persists”可以是另一个函数,例如 sleep(10)。我想检查调用顺序,而不是该项目是否以新名称保留。
  • 另外请注意,您不是在测试 mysql 是否工作,而是在测试您的代码库是否可以访问它,所以只要您传入一个有效的对象,并且在返回时没有收到错误,您就不会确实需要验证数据,只要您在输出时对其进行验证。 (你只是测试功能,分块,而不是一举测试整个事情)

标签: php unit-testing mocking phpunit


【解决方案1】:

嗯...不确定这是否是最好/最干净的方法,但最近我需要检查方法之间的顺序,这对我有用:你可以简单地拥有一个变量并通过引用来使用它方法。例如:

$name=null;
$mock1 = $this
    ->getMockBuilder(Entity::class)
    ->setMethods(['setName'])
    ->getMock();
$mock1->expects($this->any())
    ->method('setName')
    ->willReturnCallback(function($value) use (&$name) {
        $name = $value;
    });
$mock2 = $this
    ->getMockBuilder(EntityManager::class)
    ->setMethods(['persist'])
    ->getMock();
$mock2->expects($this->any())
    ->method('persist')
    ->willReturnCallback(function($object) use (&$name) {
        $this->assertNotNull($name);
    });

至少这应该可以解决问题。请注意,如果您使用相同的变量创建更多模拟来保存名称,它将失败。另一种选择是在第一个模拟中包含一个函数以返回存储在名称中的值并在第二个模拟中调用该函数。这并不完美,但仍然更安全。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    • 2019-11-15
    • 2016-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-04
    相关资源
    最近更新 更多