Разрешение DbContext в тестовом проекте возвращает DbContext с неправильным параметром connectionString

У меня есть тестовый проект, в котором используется IClassFixtureуниверсального фабричного класса. Например

public class WeatherForecastAcceptanceTest
    : IClassFixture<WebApi1ApplicationFactory<Startup>>, IDisposable
{
    .....
}

после Startup класс выполняет ConfigureServices а также Configure он выполняет ConfigureWebHost, где я удаляю исходный DbContext и добавляю новый, который работает в памяти.

public class WebApi1ApplicationFactory<TStartup>
    : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            //remove the injected DbContext and inject in-memory
            services.RemoveAll(typeof(DbContext));
            var connection = new SqliteConnection("Data Source=:memory:");
            services.AddDbContext<WebApi1DbContext>(
                options => options.UseSqlite(connection));

            var sp = services.BuildServiceProvider();
            using (var scope = sp.CreateScope())
            {
                //ERROR HERE WITH THE RESOLVED DbContext
                using (var dbContext = scope.ServiceProvider
                    .GetRequiredService<WebApi1DbContext>())
                {
                    try
                    {
                        dbContext.Database.OpenConnection();
                        dbContext.Database.EnsureCreated();
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
            }
        });
    }
}

DbContext, который я разрешаю, имеет исходную connectionString вместо InMemory, в результате все мои тесты вставляют контент в мою исходную базу данных.

Вот как я использую свой WebApplicationFactory

public class WeatherForecastAcceptanceTest : IClassFixture<WebApi1ApplicationFactory<Startup>>, IDisposable
    {
        private WebApi1ApplicationFactory<Startup> _factory;
        private HttpClient _client;

        public WeatherForecastAcceptanceTest(WebApi1ApplicationFactory<Startup> factory)
        {
            _factory = factory;
            _client = factory.CreateClient();
        }

        [Fact]
        public async Task GetAll_ReturnsElements_WhenPostWasExecutedSucessfully()
        {
            // Arrange
        var weatherForecastForCreationDto = CreateRandomWeatherForecastForCreationDto();

        var content = new JsonContent(weatherForecastForCreationDto);
        //setting the content-type header
        content.Headers.ContentType = new MediaTypeWithQualityHeaderValue(HttpMediaTypes.WeatherForecastType1);

        //create an object
        using (var client = _factory.CreateClient())
        {
            //act
            var responsePost = await _client.PostAsync(ApiRoutes.WeatherForecast.CreateWeatherForecast, content);
            //assert
            responsePost.StatusCode.Should().Be(StatusCodes.Status201Created);
        }

        //check that the object was inserted
        using (var client = _factory.CreateClient())
        {
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(HttpMediaTypes.WeatherForecastType1));
            // Act
            var response = await _client.GetAsync(ApiRoutes.WeatherForecast.GetWeatherForecast);

            // Assert
            response.StatusCode.Should().Be(StatusCodes.Status200OK);
            var returnedGet = await response.Content.ReadAsAsync<WeatherForecastDto[]>();
            returnedGet.Should().Contain(dto => dto.Summary == weatherForecastForCreationDto.Summary);
        }
        }

        public void Dispose()
        {
            _client?.Dispose();
            _factory?.Dispose();
        }
    }

Как я могу разрешить введенный DbContext в памяти?

1 ответ

После решения этой проблемы в течение некоторого времени, основываясь на документации, это то, что они предлагают

  1. При запуске прочтите переменную тестовой среды, как при производстве или разработке, и введите правильный DbContext для этого.

Например, чтобы вставить DBContext в память с помощью Sqlite.

    if (_env.IsEnvironment("Test"))
    {
         var connection = new SqliteConnection(connectionDb);
         services.AddDbContextPool<WebApi1DbContext>(options => options.UseSqlite(connection));
    }
  1. Вместо того, чтобы пытаться удалить DbContext таким образом, идея состоит в том, чтобы попытаться установить переменную среды в WebApplicationFactory, потому что AddDbContext устанавливает больше зависимостей от контейнера, которые RemoveAll не рассматривает.
public class WebApi1ApplicationFactory<TStartup>
        : WebApplicationFactory<TStartup> where TStartup : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.UseEnvironment("Test");

            builder.ConfigureServices(services =>
            {
                //DbContext in-memory is injected taking in consideration the Test environment.
                var sp = services.BuildServiceProvider();

                using (var scope = sp.CreateScope())
                {
                    using (var dbContext = scope.ServiceProvider.GetRequiredService<WebApi1DbContext>())
                    {
                        try
                        {
                            dbContext.Database.OpenConnection();
                            dbContext.Database.EnsureCreated();
                        }
                        catch (Exception ex)
                        {
                            //Log errors or do anything you think it's needed
                            throw;
                        }
                    }
                }
            });
        }
    }

Это действие позволит вам использовать DbContext для получения нужного DbContext для тестовой среды.

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