这是我尝试测试的类的高度简化版本:
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,并且仍然可以获得功能。