Запуск миграции в Startup.cs не работает с тестами с использованием WebApplicationFactory

#c# #asp.net-core #testing #entity-framework-core #integration-testing

Вопрос:

Я написал несколько интеграционных тестов для своего приложения ASP .NET Core, используя xUnit и WebApplicationFactory<Startup> класс. Потратив много времени на выяснение того, почему я получаю много SqlServerExceptions всякий раз, когда они запускаются в первый раз (т. Е. Когда база данных еще не существует), я понял, что проблема в том, что запуск context.Database.Migrate() в моем Startup.cs не очень хорошо работает с фабрикой. Я думаю, что, возможно, это связано с параллельными тестами и состоянием гонки, в результате чего две фабрики думают, что базы данных еще нет, и пытаются выполнить одни и те же миграции.

Я получаю такие ошибки, как следующие:

 Microsoft.Data.SqlClient.SqlException : Database 'MyApplicationDB' already exists. Choose a different database name.
...
Microsoft.Data.SqlClient.SqlException : There is already an object named 'AspNetRoles' in the database.
...
Microsoft.Data.SqlClient.SqlException : There is already an object named '__EFMigrationsHistory' in the database.
 

и т.д.

Я «решил» проблему, удалив шаг миграции при запуске и вместо этого запустив миграции с помощью интерфейса dotnet командной строки и запустив dotnet test .

Мой вопрос: Есть ли способ настроить WebApplicationFactory s так, чтобы они хорошо взаимодействовали друг с другом, когда в классе происходит этап миграции Startup ? Или миграция при запуске вообще плохая идея?

Комментарии:

1. Да… не проводите тесты параллельно.

2. Какую версию .net core вы используете, вы можете прочитать в этой статье, там есть хорошие примеры и пояснения, которые могут вам помочь: andrewlock.net/converting-integration-tests-to — сетевое ядро-3/

3. @Chaodeng что-то пошло не так с вашей гиперссылкой. andrewlock.net/converting-integration-tests-to-net-core-3

Ответ №1:

Может быть, вы могли бы воспользоваться InMemoryDatabase ? В этом случае вы можете сделать что-то подобное в производном WebApplicationFactory :

 protected override void ConfigureWebHost(IWebHostBuilder builder)
{
    builder.ConfigureServices(services =>
    {
        services.AddDbContext<IdentityContext>(o =>
        {
            // Make sure that every test has its own database to prevent concurrency issues in tests.
            var inMemoryDbName = Guid.NewGuid().ToString();
            o.UseInMemoryDatabase(inMemoryDbName);
        });
    });
}
 

Комментарии:

1. Спасибо, я попробую, когда представится возможность.