我在模拟重载的__get($index(方法时遇到了一个问题。要模拟的类和使用它的测试系统的代码如下:
<?php
class ToBeMocked
{
protected $vars = array();
public function __get($index)
{
if (isset($this->vars[$index])) {
return $this->vars[$index];
} else {
return NULL;
}
}
}
class SUTclass
{
protected $mocky;
public function __construct(ToBeMocked $mocky)
{
$this->mocky = $mocky;
}
public function getSnack()
{
return $this->mocky->snack;
}
}
测试如下:
<?php
class GetSnackTest extends PHPUnit_Framework_TestCase
{
protected $stub;
protected $sut;
public function setUp()
{
$mock = $this->getMockBuilder('ToBeMocked')
->setMethods(array('__get')
->getMock();
$sut = new SUTclass($mock);
}
/**
* @test
*/
public function shouldReturnSnickers()
{
$this->mock->expects($this->once())
->method('__get')
->will($this->returnValue('snickers');
$this->assertEquals('snickers', $this->sut->getSnack());
}
}
真正的代码稍微复杂一点,尽管不算太复杂,因为它的父类中有"getSnacks(("。但这个例子就足够了。
问题是,当使用PHPUnit执行测试时,我会收到以下错误:
Fatal error: Method Mock_ToBeMocked_12345672f::__get() must take exactly 1 argument in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php(231)
当我调试时,我甚至无法达到测试方法。它似乎在设置模拟对象时失败了。
有什么想法吗?
__get()
接受一个参数,因此您需要为mock提供一个:
/**
* @test
*/
public function shouldReturnSnickers()
{
$this->mock->expects($this->once())
->method('__get')
->with($this->equalTo('snack'))
->will($this->returnValue('snickers'));
$this->assertEquals('snickers', $this->sut->getSnack());
}
with()
方法为PHPUnit中的模拟方法设置参数。您可以在测试双打部分找到更多详细信息。
这有点隐藏在评论中,但@dfmuir的回答让我走上了正轨。如果使用回调,模拟__get
方法是直接的。
$mock
->method('__get')
->willReturnCallback(function ($propertyName) {
switch($propertyName) {
case 'id':
return 123123123123;
case 'name':
return 'Bob';
case 'email':
return 'bob@bob.com';
}
}
);
$this->assertEquals('bob@bob.com', $mock->email);
看看模拟的魔术方法__get。可能您从另一个未正确模拟的对象中调用了另一个__get方法。
您在GetSnackTest
类的setUp
方法中所做的操作不正确。如果你想执行__get
方法的代码(我想这将是你测试的重点>(,你必须改变在setup
方法中调用setMethods
的方式。以下是完整的解释,但以下是相关部分:
传递包含方法名的数组
您已确定的方法:
都是存根,默认情况下全部返回null,容易被覆盖
因此,您需要通过传递null
或通过传递一个数组来调用setMethods
,该数组包含一些方法(真正想要存根的方法(,但不是-__get
(因为您实际上希望执行该方法的代码(。
在shouldReturnSnickers
方法中,您只需要调用$this->assertEquals('snickers', $this->sut->getSnack());
,而不需要前面的带有expect
部分的行。这将确保__get
方法的代码得到实际执行和测试。
使用AnyParameters((方法可以帮助您,这是正确的:
$this->mock -> expects($this -> once())
-> method('__get') -> withAnyParameters()
-> will($this -> returnValue('snikers'));