У меня есть простой PHP-класс, который обертывает доступ к базе данных для извлечения пользователя и хочет его протестировать. В настоящее время у меня есть следующий код:
Класс для тестирования:
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(); } }
Единичный тест:
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)); } }
Однако теперь модульный тест завершился неудачно, если позже я решил изменить способ использования шлюза таблицы (например, использовать select(['id = ?' => $id]
). Это связывает модульный тест с деталью реализации getUserWithId($id)
которого следует избегать.
Какова была бы наилучшая практика для предотвращения тестирования модуля в зависимости от детали реализации? Стоит ли пытаться настроить фактическую тестовую базу данных, с которой может протестировать единичный тест (что также сильно замедлит выполнение теста), или есть лучший способ издеваться над табличным шлюзом?
Не издевайтесь над кодом, который у вас нет! * Для классов, использующих базу данных, вам необходимо написать тесты интеграции. Хорошо, что это заставит вас отделить доступ БД от другой логики.
* Это фактический совет из книги «Растущее объектно-ориентированное программное обеспечение, ориентированное на тесты», подкрепленное моим собственным опытом написания тестов для кода, использующего Doctrine's Entity Manager