PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount any,什么时候使用它?

时间:2017-02-13 14:26:03

标签: php testing phpunit

刚找到PHPUnit_Framework_TestCase::any

  

返回一个匹配器,当匹配它的方法被执行零次或多次时匹配。

据我所知,方法总是被调用"零次或多次",我从未调用方法-1次或更少次。所以这个匹配器应该始终匹配。为什么会存在以及何时使用它?

3 个答案:

答案 0 :(得分:1)

以下是一个小代码示例,其中显示了方法::method()

的情况
class SomeClass
{
    public function method(){
        // smth is being done here;
    }
}

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    private $mock;

    public function setUp(){
        $this->mock = $this->getMockBuilder('SomeClass')
                           ->getMock();
    }

    /**
     * @test
     */
    public function canStub(){
        $this->mock->expects($this->any())
                   ->method('method')
                   ->willReturn(true);
        $this->assertTrue($this->mock->method());
    }

    /**
     * @test
     */
    public function willCauseFatalError(){
        $this->mock->method('method')
                   ->willReturn(true);
        $this->assertTrue($this->mock->method());
    }
}

第二次测试将给出Fatal error: Call to a member function willReturn() on null

更重要的是,如果SomeClassmethod旁边有任何其他方法,则还需要通过->expects($this->any())...嘲笑

答案 1 :(得分:0)

该场景基本上是关于一个模拟对象,其中被调用的方法不参与测试场景(可能被调用一次或多次超出了测试用例的范围)。

例如:

{{1}}

希望这个帮助

答案 2 :(得分:0)

class FooTest {
    public function testSomething() {
        $mock = $this->getMockCollaborator();
        $foo = new Foo($mock, false);
        // make asserts on $foo with "false" state
        // maybe this calls $mock->getName() 4 times
    }
    public function testAnotherSomething() {
        $mock = $this->getMockCollaborator();
        $foo = new Foo($mock, true);
        // make more asserts on $foo with "true" state
        // maybe this calls $mock->getName() 12 times
    }
    protected function getMockCollaborator() {
        $mock = $this->getMock(Collaborator::class);
        $mock->expects($this->any())->method('getType')->willReturn(1);
        $mock->expects($this->any())->method('getName')->willReturn('Test');
        return $mock;
    }
}

对于任何特定的测试用例,您可能确切地知道应该调用协作者的方法的次数。但是,在测试用例之间共享模拟协作者通常很方便。当模拟如此共享时,简单地让方法被调用任意次而不是特定次数可能更方便。

为什么要指定调用方法的次数?

三个原因。首先,我们设定了对模拟协作者的期望,以确保被测系统正确地与协作者交互。虽然对通话计数的肆意验证可能是code smell,但在协作者有副作用时进行验证至关重要。例如:

  • 确保只触发一次事件
  • 确保只提交一次
  • 确保状态被查询两次(前后)
  • 和其他人。

其次,隔离框架可能会更快失败。这是理想的:测试越接近有缺陷的代码越好。这"快速失败" the paper that introduced mock objects中具体讨论了基本原理:

  

另一方面,模拟实现可以在每次与域代码交互时测试断言,因此更有可能在正确的时间失败并生成有用的消息。这样可以轻松跟踪故障的具体原因,尤其是故障消息还可以描述预期值和实际值之间的差异。例如,在上面的小部件代码中,模拟小部件知道它应该只被轮询一次,并且一旦发生第二次轮询就会失败。

第三,在PHPUnit中,如果模拟类包含一个名为method的方法,则必须在调用expects之前专门调用method。根据{{​​3}}:

  

如果原始类确实声明了一个名为"方法"的方法。然后必须使用$stub->expects($this->any())->method('doSomething')->willReturn('foo');

指定any和不指定规则有什么区别?

在PHPUnit中,没有任何内容:any是默认状态。 Mockery与其documentation匹配器相同。但是,并非所有隔离框架都遵循此原则。 IIRC,Moq的默认呼叫计数期望为1,如果"任何"适用。