【问题标题】:PHPUnit - Mocking a database functionPHPUnit - 模拟数据库函数
【发布时间】:2013-02-23 21:22:47
【问题描述】:

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

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() 方法的对象(正如pdostatement 目前所做的那样)。但是,如何在不将方法的实现暴露给测试的情况下进行测试呢?

【问题讨论】:

    标签: php pdo tdd phpunit


    【解决方案1】:

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

    【讨论】:

    • 这当然使测试变得不那么脆弱,但这意味着与应用程序代码一起测试 PDO,它并不是真正的单元测试,因为被测试的代码不是孤立的。也就是说,这绝对是比模拟 PDO 更好的解决方案。
    猜你喜欢
    • 2019-04-06
    • 2017-01-13
    • 2011-10-24
    • 2016-01-30
    • 2015-10-03
    • 2020-05-08
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多