I have a simple PHP-Class that wraps the access to the database to retrieve a user and want to unit-test it. I currently have the following code:
The class to test:
class UserTable {
protected $tableGateway;
public function __construct(\Zend\Db\TableGateway\TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}
public function getUserWithId($id) {
return $this->tableGateway->select(['id' => $id])->current();
}
}
The unit test:
class UserTableTest extends \PHPUnit_Framework_TestCase {
public function testGetUserWithIdReturnsCorrectUser() {
$user = new User();
$resultSet = new ResultSet();
$resultSet->initialize([$user]);
$mockTableGateway = $this->getMock('\Zend\Db\TableGateway\TableGateway', ['select'], [], '', false);
$mockTableGateway->expects($this->once())->method('select')->with(['id' => 1])->willReturn($resultSet);
$userTable = new UserTable($mockTableGateway);
$this->assertEquals($user, $userTable->getUserWithId(1));
}
}
However, now the unit test would fails if I later decided to change the way I use the table gateway (e.g. use select(['id = ?' => $id]
). This binds the unit test to an implementation detail of getUserWithId($id)
which should be avoided.
What would be best practice to prevent the unit test from depending on an implementation detail? Is it worth the effort to set up an actual testing database that the unit test can run against (which will also slow down the execution of the test dramatically) or is there a better way to mock the table gateway?