Phpunit,mock,willReturnCallback()没有按预期工作

时间:2015-04-07 19:54:22

标签: php mocking phpunit

类:

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  )

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

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

1 个答案:

答案 0 :(得分:1)

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

运行测试后,PHPUnit会检查模拟器上的参数调用。因此它存储了方法调用中使用的参数的副本。在回调中,您指的是变量的引用。因此PHPUnit在mock中存储自己的引用副本以进行检查。在后续调用函数时,变量不仅会更新,而且还会存储PHPUnit存储的值。因此,当它检查使用适当的参数调用模拟时,它会根据参考中存储的值(即最终值)而不是最初使用的值进行检查。

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

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

    $x = $mock->methodd();

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

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

无论如何,针对您的具体问题的修复方法是检查回调中的参数值,而不是使用with()