类:
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。
我不知道它可以是什么。换句话说,我想修改一个"reference"参数,并检查它:)
问题不直接与willReturnCallback()
有关。你的问题是你在通过参考来传递东西。如果您查看失败消息,它会告诉您传递给方法m1
的参数与预期不匹配。据说数组不是空的。
PHPUnit在测试运行后检查mock上的参数调用。因此,它存储了方法调用中使用的参数的副本。在回调中,您引用的是变量的引用。因此PHPUnit将自己的引用副本存储在mock中进行检查。在对函数的后续调用中,不仅会更新变量,还会更新PHPUnit存储的值。因此,当它检查mock是否用正确的参数调用时,它会对照存储在引用中的值进行检查,该值是最终值,而不是最初使用的值。
要解决此问题,请将测试更改为:
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()
。