我正在尝试使用
PHPUnit对mapper类进行单元测试.
我可以轻松地模拟将在mapper类中注入的PDO实例,但我无法弄清楚如何模拟PreparedStatement类,因为它是由PDO类生成的.
我可以轻松地模拟将在mapper类中注入的PDO实例,但我无法弄清楚如何模拟PreparedStatement类,因为它是由PDO类生成的.
在我的情况下,我已经扩展了PDO类,所以我有这个:
public function __construct($dsn,$user,$pass,$driverOptions)
{
//...
parent::__construct($dsn,$driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,array('Core_Db_Driver_PDOStatement',array($this)));
}
关键是Core_Db_Driver_PDOStatement没有注入PDO类的构造函数中,它是静态实例化的.即使我这样做:
public function __construct($dsn,$driverOptions,$stmtClass = 'Core_Db_Driver_PDOStatement')
{
//...
parent::__construct($dsn,array($stmtClass,array($this)));
}
…它仍然是一个静态的实例,因为我无法传递我自己的预处理语句类的模拟实例.
任何的想法 ?
编辑:
解决方案,改编自anwser:
/**
* @codeCoverageIgnore
*/
private function getDbStub($result)
{
$STMTstub = $this->getMock('PDOStatement');
$STMTstub->expects($this->any())
->method('fetchAll')
->will($this->returnValue($result));
$PDOstub = $this->getMock('mockPDO');
$PDOstub->expects($this->any())
->method('prepare')
->will($this->returnValue($STMTstub));
return $PDOstub;
}
public function testGetFooById()
{
$arrResult = array( ... );
$PDOstub = $this->getDbStub($arrResult);
}
如果你可以模拟PDO类,只需模拟pdo类及其所有依赖项.因为您通过模拟定义输入和输出,所以不需要关心pdo类的语句类或构造函数.
所以你需要一个返回模拟对象的模拟对象.
它可能看起来有点令人困惑,但是因为你应该只测试被测试的类所做的事情,而你没有别的东西可以解决你的数据库连接的所有其他部分.
在这个例子中,你想弄清楚的是:
>准备叫吗?
> fetchAll调用什么准备返回?
>该调用的结果是否返回?
如果是这样:一切都好.
<?PHP
class myClass {
public function __construct(ThePDOObject $pdo) {
$this->db = $pdo;
}
public function doStuff() {
$x = $this->db->prepare("...");
return $x->fetchAll();
}
}
class myClasstest extends PHPUnit_Framework_TestCase {
public function testDoStuff() {
$fetchAllMock = $this
->getMockBuilder("stdClass" /* or whatever has a fetchAll */)
->setMethods(array("fetchAll"))
->getMock();
$fetchAllMock
->expects($this->once())->method("fetchAll")
->will($this->returnValue("hello!"));
$mock = $this
->getMockBuilder("ThePDOObject")
->disableOriginalConstructor()
->setMethods(array("prepare"))
->getMock();
$mock
->expects($this->once())
->method("prepare")
->with("...")
->will($this->returnValue($fetchAllMock));
$x = new myClass($mock);
$this->assertSame("hello!",$x->doStuff());
}
}