【问题标题】:Prophecy - Expect that no method will be called on an object预言 - 期望不会在对象上调用任何方法
【发布时间】:2020-11-25 14:53:30
【问题描述】:

现在我在 PHPUnit 中使用以下代码来期望在 mock 上不会调用任何方法:

$object = $this->createMock(ClassA:class);
$object->expects($this->never())->method($this->anything());

到目前为止,我还没有找到在 Prophecy 中实现相同结果的方法。到目前为止,我只能测试特定方法的假设,而不是上面示例中的所有方法。

目前我正在使用以下自定义断言来测试是否没有调用任何方法。 Prophecy 的 ObjectProphecy 公开了一种方法来获取对特定函数的所有调用,因此我使用反射来获取类上的所有方法,而不是每个方法的每次调用。如果之后调用数组为空,我知道没有调用任何方法。该方法现在看起来像这样:

public function assertNoMethodHasBeenCalled(ObjectProphecy $prophecy, string $className)
{
    $methods = get_class_methods($className);

    $calls = [];
    foreach ($methods as $method) {
        $reflectionMethod = new \ReflectionMethod($className, $method);
        $numArgs = count($reflectionMethod->getParameters());
        $calls = array_merge(
            $calls,
            $prophecy->findProphecyMethodCalls(
                $method,
                new ArgumentsWildcard(array_fill(0, $numArgs, Argument::any()))
            )
        );
    }

    $this->assertEmpty($calls);
}

到目前为止,它适用于我有限的样本量,但我对此并不满意。我觉得应该有一种更简单的方法来实现相同的结果。

【问题讨论】:

  • 你能解释一下为什么你必须检查这个吗?也许举个小例子会有所帮助。
  • @PhilipWeinke 我有一个更新对象的函数,我试图确保当满足某个条件时,不会触及该对象(=> 没有执行任何设置器)
  • 既然你说的是setter,听起来好像是某种数据对象。您可能只是传入真实对象而不是模拟对象并断言它没有更改。
  • 很好的解决方案,谢谢!不知道 PHPUnit 的对象比较如此简单。基于一些快速测试和谷歌搜索 assertEquals 似乎做得很好。比我的呼叫检查器更容易和(可能)更可靠的解决方案。其他人也更容易理解;)
  • 很高兴我能帮上忙 :)

标签: php testing mocking phpunit prophecy


【解决方案1】:

据我所知,使用 Prophecy 实现这一目标并不简单。

就预期而言,Prophecy 的工作方式与 PHPUnit 的模拟不同。一旦您设置了期望,对您的模拟的每次调用都不是预测或承诺,都将通过测试。给定以下对象预言:

$prophecy = $this->prophesize(ClassA::class);
$prophecy->methodA()->shouldNotBeCalled();

$objectA = $prophecy->reveal();

两者

$objectA->methodA();

$objectA->methodB();

将无法通过测试。

因此,当您不设置任何期望时,您必须像以前一样手动检查呼叫。

【讨论】:

  • 感谢您的示例和澄清!我想我会保持原样,因为到目前为止我只有少数情况需要这样做。我可能会为我的断言方法添加一些测试,以确保它确实按预期工作。
猜你喜欢
  • 2016-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
相关资源
最近更新 更多