Phpunit、mock、willReturnCallback() 没有按预期工作
Phpunit, mock, willReturnCallback() doesnt work as expected
class:
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 在测试 运行 之后检查模拟上的参数调用。因此它存储了方法调用中使用的参数的副本。在您的回调中,您指的是变量的引用。所以 PHPUnit 将自己的引用副本存储在 mock 中以供检查。在后续调用该函数时,不仅变量会更新,PHPUnit 存储的值也会更新。因此,当它检查是否使用正确的参数调用模拟时,它会检查存储在引用中的值,该值是最终值,而不是最初使用的值。
要解决此问题,请将您的测试更改为:
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,但您不应该模拟属于您正在测试的 class 一部分的代码。 methodd()
使用这些函数的事实是 class 的一个实现细节。如果您决定将 m1()
或 m2
中的逻辑移动到 methodd()
中,您的测试应该会通过。模拟这些方法会使您的测试变得不那么有用。由于 class 中的代码更改而不是 functionality/bugs 中的实际更改,它们可能会失败。
无论如何,解决您的具体问题的方法是检查回调中的参数值,而不是使用 with()
。
class:
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 在测试 运行 之后检查模拟上的参数调用。因此它存储了方法调用中使用的参数的副本。在您的回调中,您指的是变量的引用。所以 PHPUnit 将自己的引用副本存储在 mock 中以供检查。在后续调用该函数时,不仅变量会更新,PHPUnit 存储的值也会更新。因此,当它检查是否使用正确的参数调用模拟时,它会检查存储在引用中的值,该值是最终值,而不是最初使用的值。
要解决此问题,请将您的测试更改为:
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,但您不应该模拟属于您正在测试的 class 一部分的代码。 methodd()
使用这些函数的事实是 class 的一个实现细节。如果您决定将 m1()
或 m2
中的逻辑移动到 methodd()
中,您的测试应该会通过。模拟这些方法会使您的测试变得不那么有用。由于 class 中的代码更改而不是 functionality/bugs 中的实际更改,它们可能会失败。
无论如何,解决您的具体问题的方法是检查回调中的参数值,而不是使用 with()
。