Изоляция тестов: транзакции, Respawn, сиды

↑ 4.3 Тестирование слоя данных · ← Предыдущая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Как сделать тесты независимыми и повторяемыми при общей БД.

Объяснение

СпособКакПлюсыМинусы
Транзакция с откатомкаждый тест в транзакции, rollback в концеочень быстроне подходит для кода, сам управляющий транзакциями
Respawnочистка данных (DELETE/TRUNCATE) перед тестомуниверсальночуть медленнее
БД на тест / схема на тестполная изоляциямаксимально надёжнодорого
Пересоздание контейнерачистое состояниедолготолько для редких тестов
public class OrdersTests(PgFixture fx) : IAsyncLifetime
{
    private Respawner _respawner = default!;
    public async Task InitializeAsync()
    {
        await using var conn = new NpgsqlConnection(fx.ConnectionString);
        await conn.OpenAsync();
        _respawner = await Respawner.CreateAsync(conn, new RespawnerOptions { DbAdapter = DbAdapter.Postgres, TablesToIgnore = ["__EFMigrationsHistory"] });
        await _respawner.ResetAsync(conn);
    }
    public Task DisposeAsync() => Task.CompletedTask;
}

Сиды

  • Справочники — часть миграций или отдельный seed; тестовые данные создавайте явно в тесте (builder-ы), а не полагайтесь на общий «мир».
  • Каждый тест создаёт только нужные ему данные и уникальные значения (GUID), тогда параллельный запуск безопасен.

Нюансы и подводные камни

  • Общие данные между тестами — источник flaky.
  • Порядок тестов не должен влиять на результат.
  • Параллельные тесты на одной БД: изолируйте по схеме или отключайте параллелизм коллекции.
  • Не забудьте исключить таблицу истории миграций при очистке.

Практика

  1. Подключите Respawn и убедитесь, что тесты не зависят друг от друга.
  2. Сравните время: rollback, Respawn, пересоздание БД.
  3. Напишите builder для сложного агрегата с разумными значениями по умолчанию.

Вопросы с ответами

Связанные темы