这是我正在编写测试套件的类的构造函数(它扩展了mysqli):
function __construct(Config $c)
{
// store config file
$this->config = $c;
// do mysqli constructor
parent::__construct(
$this->config['db_host'],
$this->config['db_user'],
$this->config['db_pass'],
$this->config['db_dbname']
);
}
传递给构造函数的Config
类实现了内置于php的arrayaccess
接口:
class Config implements arrayaccess{...}
如何模拟/存根Config
对象?我应该使用哪个以及为什么?
提前致谢!
答案 0 :(得分:15)
如果您可以从数组中轻松创建Config
实例,那将是我的偏好。虽然您希望在实际情况下单独测试您的单元,但Config
之类的简单协作者应该足够安全,可以在测试中使用。设置它的代码可能比同等的模拟对象更容易读写(更不容易出错)。
$configValues = array(
'db_host' => '...',
'db_user' => '...',
'db_pass' => '...',
'db_dbname' => '...',
);
$config = new Config($configValues);
话虽这么说,你嘲笑一个实现ArrayAccess
的对象就像你对任何其他对象一样。
$config = $this->getMock('Config', array('offsetGet'));
$config->expects($this->any())
->method('offsetGet')
->will($this->returnCallback(
function ($key) use ($configValues) {
return $configValues[$key];
}
);
您也可以使用at
强制执行特定的访问顺序,但这样做会使测试变得非常脆弱。
答案 1 :(得分:1)
基本上,您可以模拟ArrayAccess
接口方法。只需记住您可能想同时模拟offsetGet
和offsetExists
(在使用它之前,您应始终检查一个数组键是否存在,否则可能会遇到E_NOTICE
错误和不可预测的行为)您的代码(如果不存在)。
$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);
$thingyWithArrayAccess->method('offsetGet')
->with('your-offset-here')
->willReturn('test-value-1');
$thingyWithArrayAccess->method('offsetExists')
->with($'your-offset-here')
->willReturn(true);
当然,您可以在测试中使用一个真实的数组,例如
$theArray = [
'your-offset-here-1' => 'your-mock-value-for-offset-1',
];
$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);
$thingyWithArrayAccess->method('offsetGet')
->willReturnCallback(
function ($offset) use ($theArray) {
return $theArray[$offset];
}
);
$thingyWithArrayAccess->method('offsetExists')
->willReturnCallback(
function ($offset) use ($theArray) {
return array_key_exists($offset, $theArray);
}
);