2

Here's a highly simplified version of the class I'm trying to test:

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);

    }


}

So, my question is, how do I write a test for this class?

I can mock PDO, like this:

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);
}

The problem with this approach is that exposes the internal workings of the findById() method to the test, and if they change the test will fail even though the method may have been refactored to work correctly.

In order for the findById() method to succeed, it must call pdo::prepare() which must return an object that has an execute() and fetch() method (as the pdostatement does at the moment). However, how can I test this without exposing the implementation of the method to the test?

4

1 回答 1

0

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

于 2013-03-11T08:50:23.690 回答