PHPUnit - 如何模拟 PDO 准备好的语句

标签 php mocking pdo phpunit prepared-statement

我正在尝试使用 PHPUnit 对映射器类进行单元测试。 我可以轻松模拟将注入(inject)到映射器类中的 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 没有注入(inject)到 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);
}

最佳答案

如果您可以模拟 PDO 类,只需模拟出 pdo 类及其所有依赖项。由于您通过模拟定义输入和输出,因此无需关心语句类或 pdo 类的构造函数。

所以你需要一个返回模拟对象的模拟对象。

这可能看起来有点困惑,但由于您应该只测试被测类的功能,而没有其他任何东西,您几乎可以摆脱数据库连接的所有其他部分。

在这个例子中,你想弄清楚的是:

  • 是否调用了 prepare?
  • 是否在 prepare 返回时调用了 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());


    }

}

关于PHPUnit - 如何模拟 PDO 准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5339178/

相关文章:

php - 使用 PHP Pear::Mail 多语言(泰米尔语)邮件发送,修剪收件箱邮件中的正文内容

c# - 如何使用 FakeItEasy 伪造 Action <>

android - 如何停止测试位置提供程序

php - Mysql group by 并计算单独列上的尝试

php - MySQL 选择早于 x 天的行、分组依据、排序依据和限制

php - 更改 curl SSL 版本

java - 为什么mockito在 stub 时调用父方法

Symfony2 : transactions fail with "There is no active transaction."

php - (PHP) 使用两个表进行登录查询;其他用户未登录?

php - 如何正确发送小数到mysql数据库?