PHPUnit - 如何模拟 PDO 准备好的语句
我正在尝试使用 PHPUnit 对映射器类进行单元测试。 我可以轻松地模拟将注入映射器类中的 PDO 实例,但我不知道如何模拟PreparedStatement 类,因为它是由 PDO 类生成的。
在我的例子中,我扩展了 PDO 类,所以我有这个:
public function __construct($dsn, $user, $pass, $driverOptions)
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
array('Core_Db_Driver_PDOStatement', array($this)));
}
要点是 Core_Db_Driver_PDOStatement 没有注入到 PDO 类的构造函数中,它是静态实例化的。即使我这样做:
public function __construct($dsn, $user, $pass, $driverOptions, $stmtClass = 'Core_Db_Driver_PDOStatement')
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
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);
}
I'm trying to unit test a mapper class with PHPUnit.
I can easilly mock the PDO instance that will be injected in the mapper class, but I can't figure out how to mock the PreparedStatement class, as it's generated by the PDO class.
In my case I've extended the PDO class, so I have this:
public function __construct($dsn, $user, $pass, $driverOptions)
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
array('Core_Db_Driver_PDOStatement', array($this)));
}
The point is that Core_Db_Driver_PDOStatement is not injected in the constructor of the PDO Class, it's instanciated statically. And even if I do this:
public function __construct($dsn, $user, $pass, $driverOptions, $stmtClass = 'Core_Db_Driver_PDOStatement')
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
array($stmtClass, array($this)));
}
... it's still a static instanciation as I can't pass my own mocked instance of the prepared statement class.
Any idea ?
Edit:
Solution, adapted from the 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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您可以模拟 PDO 类,只需模拟出 pdo 类及其所有依赖项即可。不需要关心语句类或 pdo 类的构造函数,因为您通过模拟定义了输入和输出。
因此,您需要一个返回模拟对象的模拟对象。
它可能看起来有点令人困惑,但由于您应该只测试正在测试的类的功能,而没有其他任何内容,因此您几乎可以摆脱数据库连接的所有其他部分。
在这个例子中,您想要弄清楚的是:
如果是这样:一切都好。
If you can mock the PDO class just mock out the pdo class and all it's dependencies. There should be no need to care about the statement class or the constructor of the pdo class since you define the input and output via the mocks.
So you need a mock object that returns a mock object.
It might look a little confusing but since you should only test what the class under testing does and nothing else you can pretty much make away with all the other parts of your DB connection.
In this example all you want to figure out is:
If so: All well.