【问题标题】:PHPUnit: Expectations orders ignored in test when same stubbed method called multiple times with different argumentsPHPUnit:当使用不同的参数多次调用相同的存根方法时,测试中忽略的期望顺序
【发布时间】:2015-03-17 05:37:06
【问题描述】:

我有一个方法(我们称之为 method2),它多次调用另一个方法(我们称之为 method1),但参数不同。

这是类,MyClass.php:

<?php

class MyClass
{

    public function method1($arg)
    {
        return 'arg was ' . $arg;
    }

    public function method2()
    {
        // Calling the first time with 'one'
        $this->method1('one');

        // Calling other functions
        // ...

        // Calling the first time with 'two'
        $this->method1('two');
    }
}

在测试时,我为 method1 创建了一个存根,以控制它被调用的方式/时间以及返回的内容。在我对method2的测试中,我按照在method2中执行代码的顺序。

这里是测试类,MyClassTest.php:

<?php

require_once 'MyClass.php';

class MyClassTest extends PHPUnit_Framework_TestCase
{

    /** @test */
    public function method2_was_called_successfully_with_one_and_then_two()
    {
        $myClassMock = $this->getMockBuilder('MyClass')
                            ->setMethods(['method1'])
                            ->getMock();

        $myClassMock->expects($this->once())
                    ->method('method1')
                    ->with($this->stringContains('one', true))
                    ->will($this->returnValue('arg was one'));

        // Testing code for the code between the two calls
        // ...

        $myClassMock->expects($this->once())
                    ->method('method1')
                    ->with($this->stringContains('two', true))
                    ->will($this->returnValue('arg was two'));

        $myClassMock->method2();
    }
}

在我的测试中,PHPUnit 似乎没有遵循这个顺序,并且被方法 1 的最后一次(在这种情况下是第二次)调用中卡住了:

有 1 次失败:

1) MyClassTest::method2_was_call_successfully_with_one_and_then_two 方法名称的期望失败等于何时 调用 1 次 调用参数 0 MyClass::method1('one') 与预期值不匹配。未能断言“一个”包含 “两个”。

/path/to/the/files/MyClass.php:14 /path/to/the/files/MyClassTest.php:28

失败!测试:1,断言:0,失败:1。

知道我在这里遗漏/做错了什么基本的事情吗?

【问题讨论】:

    标签: mocking phpunit expectations


    【解决方案1】:

    配置模拟时必须使用at() 而不是once()

        $myClassMock = $this->getMockBuilder('MyClass')
                            ->setMethods(['method1'])
                            ->getMock();
    
        $myClassMock->expects($this->at(0))
                    ->method('method1')
                    ->with($this->stringContains('one', true))
                    ->will($this->returnValue('arg was one'));
    
        $myClassMock->expects($this->at(1))
                    ->method('method1')
                    ->with($this->stringContains('two', true))
                    ->will($this->returnValue('arg was two'));
    
    
        // Testing code
        // ....
        // ....
    

    附带说明一下,在执行了一些测试代码之后配置模拟对我来说看起来很奇怪。通常的模式是配置模拟在测试开始时应该接收的所有调用。然后运行 ​​SUT 并检查是否进行了所有调用(通常最后一步是自动的)。

    【讨论】:

    • 谢谢!你能用正确的顺序编辑你的答案吗?这样我也可以借此机会改正一个坏习惯...... :)
    • 编辑了答案,只需将“测试代码”注释放在模拟配置下方即可。
    猜你喜欢
    • 1970-01-01
    • 2011-08-24
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 2015-09-17
    相关资源
    最近更新 更多