Ответ
Тестирование запросов к БД можно организовать несколькими способами, в зависимости от уровня изоляции и целей теста.
1. Моки и стабы (Unit-тесты) Используются для изоляции бизнес-логики от реальной БД. Мы мокаем слой доступа к данным (например, репозиторий или PDO).
// Пример с PHPUnit
$repositoryMock = $this->createMock(UserRepository::class);
$repositoryMock->expects($this->once())
->method('findActiveUsers')
->willReturn([
new User('John'),
new User('Jane')
]);
$service = new UserService($repositoryMock);
$result = $service->getActiveUsers();
$this->assertCount(2, $result);
2. Использование тестовой БД (Интеграционные тесты) Тесты выполняются против реальной, но изолированной базы данных (часто SQLite в памяти или Docker-контейнер). Ключевой момент — управление состоянием.
protected function setUp(): void
{
parent::setUp();
// Подключение к SQLite в памяти
$this->pdo = new PDO('sqlite::memory:');
$this->pdo->exec('CREATE TABLE users (id INTEGER, name TEXT)');
// Загрузка фикстур
$this->loadFixtures();
}
public function testFindUserById()
{
$repository = new UserRepository($this->pdo);
$user = $repository->find(1);
$this->assertEquals('John', $user->name);
}
protected function tearDown(): void
{
$this->pdo = null;
parent::tearDown();
}
3. Транзакционное тестирование Позволяет использовать ту же схему БД, что и в продакшене, с откатом изменений после каждого теста.
use PHPUnitFrameworkTestCase;
use DoctrineDBALConnection;
class TransactionalTest extends TestCase
{
private Connection $connection;
protected function setUp(): void
{
$this->connection = TestConnectionFactory::create();
$this->connection->beginTransaction(); // Начало транзакции
}
public function testComplexQuery()
{
$repository = new UserRepository($this->connection);
$repository->insert(new User('Test'));
// Тест выполняется внутри транзакции
$users = $repository->findAll();
$this->assertNotEmpty($users);
}
protected function tearDown(): void
{
$this->connection->rollBack(); // Откат всех изменений теста
parent::tearDown();
}
}
Основные практики:
- Изоляция: Каждый тест должен стартовать с предсказуемого состояния БД (фикстуры, транзакции).
- Скорость: Используйте in-memory БД для быстрых юнит-тестов.
- Проверка данных: Утверждайте не только факт выполнения запроса, но и корректность возвращённых данных.
- Тестирование ошибок: Обязательно тестируйте граничные случаи и обработку ошибок БД (например, дублирование ключа).