Как избежать зависимости тестов из-за общего scope базы данных
Что проверяют
Понимаете ли вы, почему тесты, зелёные по отдельности, падают в общем прогоне, и умеете ли изолировать их на уровне базы, а не только моками. Следом обычно спрашивают, как вы запускаете такие тесты параллельно в xUnit или NUnit.
Как отвечать
Сначала назовите причину: тесты делят одну базу, один DbContext или один DI-scope, и данные одного теста видит другой. Дальше способы изоляции, от простого к надёжному:
- транзакция с откатом: каждый тест открывает
TransactionScope(для async сTransactionScopeAsyncFlowOption.Enabled) илиBeginTransaction()и не вызываетComplete()/Commit(), всё откатывается вDispose; - сброс базы между тестами: библиотека Respawn чистит таблицы в порядке внешних ключей, это быстрее, чем пересоздавать схему;
- своя база на прогон или на воркер: Testcontainers поднимает PostgreSQL или SQL Server в Docker, миграции накатываются один раз в фикстуре;
- уникальные данные: тест создаёт свои записи с
Guidв ключах и проверяет только их, тогда общая база переживёт и параллельный запуск; - свежий scope на тест: в интеграционных тестах через
WebApplicationFactoryберитеIServiceScopeFactory.CreateScope()на каждый тест, иначе общийDbContextотдаёт сущности, закэшированные трекером изменений.
В xUnit тесты одного класса идут последовательно, а разные коллекции параллельно. Тяжёлую общую фикстуру держите в ICollectionFixture, а тесты с общим состоянием сводите в одну [Collection].
Где спотыкаются
Пишут transaction.Complete() в тестовом TransactionScope. Это как раз фиксация: данные останутся в базе, и изоляции не будет.
Предлагают EF Core InMemory как решение. Этот провайдер не реляционный: не проверяет внешние ключи, игнорирует транзакции и не выполняет SQL, поэтому тест зелёный, а прод падает. Даже SQLite in-memory ведёт себя иначе, чем PostgreSQL или SQL Server.
Не учитывают, что код под тестом сам открывает транзакции или второе соединение. Тогда откат обёрткой не срабатывает или транзакция эскалирует до распределённой, которая вне Windows не поддерживается.