【问题标题】:Phpunit, mock, willReturnCallback() doesnt work as expectedPhpunit,模拟,willReturnCallback() 没有按预期工作
【发布时间】:2015-06-12 13:18:52
【问题描述】:

类:

class TestMe
{
    public function m1 (array &$a)
    {
    }

    public function m2 (array &$a)
    {
    }

    public function methodd()
    {
        $a = array();
        $this->m1 ($a);
        $this->m2 ($a);
        return $a;
    }
}

测试:

class X extends PHPUnit_Framework_TestCase
{
    public function testMethod()
    {
        $mock = $this->getMock('TestMe', array('m1','m2'));
        $mock->expects($this->once())->method('m1')->with(array())->willReturnCallback(function (&$x) { $x['a'] = 1; });
        $mock->expects($this->once())->method('m2')->with(array('a' => 1))->willReturnCallback(function (&$x) { $x['b'] = 2; });

        $x = $mock->methodd();

        $this->assertEquals (array('a' => 1, 'b' => 2), $x);
    }
}

不知何故失败了:

有 1 次失败:

1) X::testMethod 方法名称的预期失败等于调用 1 次。 调用 TestMe::m1(Array (...)) 的参数 0 与预期值不匹配。 断言两个数组相等时失败。 - - 预期的 +++ 实际 @@@@ 大批 ( + 'a' => 1 + 'b' => 2 )

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

我不知道它会是什么。换句话说,我想修改一个“引用”参数,并检查它:)

【问题讨论】:

    标签: php mocking phpunit


    【解决方案1】:

    问题不在于willReturnCallback()。你的问题是你通过引用传递东西。如果您查看失败消息,它会告诉您传递给方法 m1 的参数与预期不匹配。表示数组不为空。

    PHPUnit 在测试运行后检查模拟的参数调用。因此它存储了方法调用中使用的参数的副本。在您的回调中,您指的是变量的引用。所以 PHPUnit 将它自己的引用副本存储在 mock 中以进行检查。在随后调用该函数时,不仅会更新变量,还会更新 PHPUnit 存储的值。因此,当它检查是否使用正确的参数调用了 mocks 时,它会检查存储在引用中的值,该值是最终值,而不是最初使用的值。

    要解决此问题,请将您的测试更改为:

        public function testMethod()
    {
        //Get a copy of the testcase to use in the callback
        $testcase = $this;
        $mock = $this->getMock('TestMe', ['m1','m2']);
        $mock->expects($this->once())
             ->method('m1')
             ->willReturnCallback(function (&$x) use ($testcase) {
                 //do your parameter checking immediately
                 $testcase->assertEquals([], $x); 
                 $x['a'] = 1; 
             });
        $mock->expects($this->once())
             ->method('m2')
             ->willReturnCallback(function (&$x) use ($testcase) {
                 //do your parameter checking immediately
                 $testcase->assertEquals(['a' => 1], $x); 
                 $x['b'] = 2; 
             });
    
        $x = $mock->method();
    
        $this->assertEquals (['a' => 1, 'b' => 2], $x);
    }
    

    尽管 IMO,您不应该模拟您正在测试的类的一部分的代码。 methodd() 使用这些函数的事实是您的类的实现细节。如果您决定将m1()m2 中的逻辑移动到methodd(),您的测试应该会通过。模拟这些方法会使您的测试变得不那么有用。它们可能由于类中的代码更改而不是功能/错误的实际更改而失败。

    无论如何,解决您特定问题的方法是检查回调中的参数值,而不是使用with()

    【讨论】:

      猜你喜欢
      • 2018-09-11
      • 1970-01-01
      • 2019-08-08
      • 1970-01-01
      • 2016-08-27
      • 2021-08-18
      • 2021-07-18
      • 1970-01-01
      • 2021-03-30
      相关资源
      最近更新 更多