Как обернуть интеграционные тесты, использующие 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"

Другие вопросы по тегам