Как обернуть интеграционные тесты, использующие TestServer, в транзакции базы данных?
Использование xUnit и TestServer
от Microsoft.AspNet.TestHost, как обернуть каждый тест в транзакцию базы данных, которую можно откатить после теста?
Вот как я создаю TestServer
:
TestServer = new TestServer(TestServer.CreateBuilder()
.UseStartup<Startup>());
Startup
это ссылка там есть Startup
из проекта веб-приложения. в ConfigureServices
метод в этом Startup
класс я добавляю EF вот так:
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TrailsDbContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
Я мог бы вытащить DbContext
обратно услуг и хранить статическую ссылку на Startup
класс, но это выглядит довольно нахально. Есть ли способ, которым я могу создать экземпляр DbContext
где я создаю TestServer
и каким-то образом веб-приложение использует это вместо того, что в Startup
учебный класс?
Изменить: я пытался создать экземпляр другого экземпляра DbContext
где я создаю TestServer
и использование этого контекста для удаления и воссоздания базы данных перед каждым тестом, но это добавляет около 10 секунд к времени выполнения каждого теста.
1 ответ
Несколько советов: самый простой подход - уничтожить тестовую базу данных в конце и воссоздать для каждого запуска теста. Это гарантирует, что загрязнение не затянется.
Но поскольку вы спросили, как это сделать, можно расширить Xunit. Xunit позволяет вам определять пользовательские тестовые случаи и тестовые прогоны. Полный ответ трудно включить в SO-ответ. Самое простое решение использует окружающие транзакции. (Опасно! Окружающие транзакции могут быть хитрыми.) В Xunit есть образец для пользовательского атрибута BeforeAfterTestAttribute, который откатывает транзакцию. https://github.com/xunit/samples.xunit/tree/master/AutoRollbackExample. Чтобы использовать окружающие транзакции, отключите настройку EF по умолчанию, которая выбрасывает, если присутствуют окружающие транзакции. (optionsBuilder.UseSqlServer().SuppressAmbientTransactionWarning()
).
Более сложное, но лучшее решение - переопределить XunitTestCaseRunner
и вводить транзакцию в каждый тестовый пример, обеспечивая откат по завершении каждого теста.
Кроме того, EF docs предоставляет пример использования поставщика InMemory для тестирования. Вы можете найти это полезным. "Тестирование в памяти: EF Core Docs"