PHPUnit中模拟对象来模拟静态方法调用?
题
我想测试管理数据库(你知道,CRUD,本质上)数据访问的类。我们正在使用的DB库恰巧有一个API,其中首先通过一个静态调用得到表对象:
function getFoo($id) {
$MyTableRepresentation = DB_DataObject::factory("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
...你的想法。
我们想测试这种方法,但嘲讽数据对象的东西,所以这(一)我们不需要为测试实际的数据库连接,以及(b)我们甚至都不需要包括DB_DataObject LIB用于测试
然而,在PHPUnit的我似乎无法得到$这个 - > getMock()来适当地设置一个静态调用。我有...
$DB_DataObject = $this->getMock('DB_DataObject', array('factory'));
...但测试仍然说未知方法“工厂”。我知道这是在创建对象,因为之前它说,它无法找到DB_DataObject。现在,它可以。但是,没有一种方法
我真正想要做的是有两个模拟对象,一个是表对象返回为好。所以,我不仅需要指定工厂是一个静态调用,而且它返回一些规定,我已经设置了其他模拟对象。
我要提一个简单的警告,我在SimpleTest的这样做了一段时间前(找不到代码)和它工作得很好。
什么给?
[UPDATE]
我开始掌握它是与预计()
解决方案
我同意你们俩,这将是最好不要使用静态调用。不过,我想我忘了提,DB_DataObject是一个第三方库,静态调用的及其的最佳实践自己的代码使用,而不是我们。还有其他的方式来使用他们的对象涉及直接构建在返回的对象。它只是留下那些该死的包括/需要在任何类文件是使用DB_DO类的语句。这吮吸,因为测试将打破(或只是没有被分离),如果你同时试图嘲弄一类在测试中相同名称的 - 至少我觉得
其他提示
当你不能改变图书馆,改变你的访问它。重构为DB_DataObject ::工厂()的所有呼叫在代码实例方法:
function getFoo($id) {
$MyTableRepresentation = $this->getTable("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
function getTable($table) {
return DB_DataObject::factory($table);
}
现在可以使用正在测试的类的局部模拟和具有getTable()返回一个模拟表对象。
function testMyTable() {
$dao = $this->getMock('MyTableDao', array('getMock'));
$table = $this->getMock('DB_DataObject', ...);
$dao->expects($this->any())
->method('getTable')
->with('mytable')
->will($this->returnValue($table));
$table->expects...
...test...
}
这是在你的代码的依赖的一个很好的例子 - 设计已经使人们无法在一个模拟的注入而不是真正的类
我的第一个建议是尝试并重构代码使用的实例,而不是一个静态调用。
什么是您的DB_DataObject类丢失(或不?)是调用工厂方法之前通过准备好的db对象二传手。你可以通过一个模拟的或定制db对象(具有相同的接口),该方式在需要时
在测试设置:
public function setUp() {
$mockDb = new MockDb();
DB_DataObject::setAdapter($mockDb);
}
在工厂()方法应该返回嘲笑DB实例。如果它不是已经集成到你的类,你可能会重构工厂()方法,以及使其工作。
您需要/包括在你的测试用例类文件DB_DataObject?如果类的PHPUnit之前不存在试图嘲笑的对象,你可以得到象这样的错误。
在PHPUnit MockFunction延长加runkit你也可以模拟静态方法。要小心,因为它是猴子打补丁,因此应该只有在极端情况下使用。不能替代良好的编程习惯。