Разрешение 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 ответ
После решения этой проблемы в течение некоторого времени, основываясь на документации, это то, что они предлагают
- При запуске прочтите переменную тестовой среды, как при производстве или разработке, и введите правильный DbContext для этого.
Например, чтобы вставить DBContext в память с помощью Sqlite.
if (_env.IsEnvironment("Test"))
{
var connection = new SqliteConnection(connectionDb);
services.AddDbContextPool<WebApi1DbContext>(options => options.UseSqlite(connection));
}
- Вместо того, чтобы пытаться удалить 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 для тестовой среды.