【发布时间】:2011-11-23 07:25:36
【问题描述】:
我想要一个 PHPUnit Mock,它像正常一样执行方法,然后在函数返回之前以某种方式修改返回值。
我有什么
我有一组派生类,如下所示:
abstract class Base
{
abstract protected function getUrl();
public function callUrl() {
$url = $this->getUrl();
// some code to call the URL here
}
}
class Foo extends Base
{
protected function getUrl() {
return "http://www.example.com/Foo";
}
}
class Bar extends Base
{
protected function getUrl() {
return "http://www.example.com/Bar";
}
}
请注意我拥有的类要复杂得多,而且我必须测试的一些项目有副作用(例如写入数据库等)。
天真、重复的代码方法
如果我只有一个派生类(例如 Foo),那么我可以执行以下操作:
class FooMock extends Foo
{
protected function getUrl() {
return parent::getUrl() . "?sandbox";
}
}
class theTest extends PHPUnit_Framework_TestCase
{
public function testIt() {
$mock = new FooMock();
// assert something
}
}
不幸的是,这意味着我需要为每个要测试的派生类指定一个特定的“Mock”类,所有这些派生类都执行完全相同的功能。
首选方法
相反,我希望能够执行以下操作:
function callback ($returnValue) {
return $returnValue . "?sandbox";
}
class theTest extends PHPUnit_Framework_TestCase
{
private $mock;
public function testFoo() {
$this->mock = $this->getMockBuilder('Foo')->getMock();
$this->setupMock();
// assert something
}
public function testBar() {
$this->mock = $this->getMockBuilder('Bar')->getMock();
$this->setupMock();
// assert something
}
public function setupMock() {
$this->mock->expects($this->any())
->method('getUrl')
->will($this->postProcessReturnValue('callback'));
}
}
PHPUnit 能做到吗?
更新:有人建议我有一个原始类的实例和一个模拟类的实例。使用原始类获取原始返回值并对其进行修改。然后将此修改后的值用作 Mock 的返回值。这不是一种可行的方法,因为类更复杂(它们有副作用,例如写入数据库)。
这不起作用的示例;
class Foo extends Base
{
$id = 0;
public function saveToDB() {
$this->id = saveToDBAndReturnId();
}
protected function getUrl() {
if ($this->id > 0) {
return "http://www.example.com/".$this->id;
}
throw new Exception("No ID");
}
}
$foo = new Foo();
$foo->saveToDB();
$url = $foo->getUrl();
显然,多次调用返回的 URL 会有所不同。我总是可以模拟saveToDB,但是当我想做的只是对getUrl 的结果进行后处理时,我开始觉得很脏。
【问题讨论】:
标签: php unit-testing phpunit