PHPUnit:当使用不同的参数多次调用同一个存根方法时,测试中忽略期望顺序
PHPUnit: Expectations orders ignored in test when same stubbed method called multiple times with different arguments
我有一个方法(我们称之为方法 2)多次调用另一个方法(我们称之为方法 1)但参数不同。
这里是class,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 中执行的顺序。
这里是测试class,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 的最后一次(本例中为第二次)调用中:
There was 1 failure:
1) MyClassTest::method2_was_called_successfully_with_one_and_then_two
Expectation failed for method name is equal to when
invoked 1 time(s) Parameter 0 for invocation MyClass::method1('one')
does not match expected value. Failed asserting that 'one' contains
"two".
/path/to/the/files/MyClass.php:14
/path/to/the/files/MyClassTest.php:28
FAILURES! Tests: 1, Assertions: 0, Failures: 1.
关于我在这里遗漏/做错的基本事情有什么想法吗?
配置 mock 时必须使用 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 并检查是否进行了所有调用(通常这最后一步是自动的)。
我有一个方法(我们称之为方法 2)多次调用另一个方法(我们称之为方法 1)但参数不同。
这里是class,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 中执行的顺序。
这里是测试class,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 的最后一次(本例中为第二次)调用中:
There was 1 failure:
1) MyClassTest::method2_was_called_successfully_with_one_and_then_two Expectation failed for method name is equal to when invoked 1 time(s) Parameter 0 for invocation MyClass::method1('one') does not match expected value. Failed asserting that 'one' contains "two".
/path/to/the/files/MyClass.php:14 /path/to/the/files/MyClassTest.php:28
FAILURES! Tests: 1, Assertions: 0, Failures: 1.
关于我在这里遗漏/做错的基本事情有什么想法吗?
配置 mock 时必须使用 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 并检查是否进行了所有调用(通常这最后一步是自动的)。