PHPUnit - 模拟数据库函数


PHPUnit - Mocking a database function

这是我尝试测试的类的高度简化版本:

class SimpleORM {
    private $table, $pdo;
    public function __construct(PDO $pdo, $table) {
        $this->pdo = $pdo;
        $this->table = $table;
    }

    public function findById($id) {
        $stmt = $this->pdo->prepare('SELECT * FROM ' . $this->table . ' WHERE ' . $this->primaryKey() . ' = :id');
        $stmt->execute(array(':id' => $id);
        return $stmt->fetch(PDO::FETCH_OBJ);
    }

}

所以,我的问题是,我如何为这个类编写测试?

我可以像这样嘲笑PDO:

public function testFindById() {
    $pdo = $this->getMock('PDO', array('prepare'));
    $stmt = $this->getMock('PDOStatement', array('execute', 'fetch'));
    $stmt->expects($this->once())->method('execute')->with($this->equalTo(array(':id' => 123)));
    $stmt->expects($this->once())->method('fetch');
    $pdo->expects($this->once())->method('prepare')
                ->with($this->equalTo('SELECT * FROM test WHERE id => :id'))
                ->will($this->returnValue($stmt));

    $mapper = new SimpleOrm($pdo, 'test');
    $mapper->findById(123);
}

这种方法的问题在于,findById()方法的内部工作原理暴露给测试,如果它们更改,即使该方法可能已被重构以正常工作,测试也会失败。

为了使 findById() 方法成功,它必须调用pdo::prepare() 必须返回具有execute()fetch()方法的对象(就像 pdo语句目前所做的那样(。但是,如何在不将方法的实现暴露给测试的情况下对此进行测试?

我会保持代码原样,并用可测试的数据预填充数据库。这样,您就不需要伪造PDO,并且仍然可以获得功能。