Reputation: 15
This is my test class(well, part that contains the problem)
public class FiltrationServiceTests:
IClassFixture<IntegrationTestWebAppFactory>,
IAsyncLifetime
{
private readonly AppDbContext _db;
private readonly Func<Task> _resetDb;
public FiltrationServiceTests(IntegrationTestWebAppFactory factory)
{
factory
.Services
.CreateScope()
.ServiceProvider
.GetRequiredService<AppDbContext>();
_db = factory.Db;
_resetDb = factory.ResetDatabase;
}
Using debugger i can see IServiceProvider which is returned by .Services line is disposed immediately in the constructor. I don't understand why.
IntegrationTestWebAppFactory:
public class IntegrationTestWebAppFactory:
WebApplicationFactory<Program>,
IAsyncLifetime
{
private readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder()
.WithImage("postgres:latest")
.WithDatabase("db")
.WithUsername("postgres")
.WithPassword("postgres")
.WithWaitStrategy(Wait.ForUnixContainer().UntilCommandIsCompleted("pg_isready"))
.WithCleanUp(true)
.Build();
public AppDbContext Db = null!;
private Respawner _respawner = null!;
private DbConnection _connection = null!;
public async Task ResetDatabase()
{
await _respawner.ResetAsync(_connection);
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
var descriptorType =
typeof(DbContextOptions<AppDbContext>);
var descriptor = services
.SingleOrDefault(s => s.ServiceType == descriptorType);
if (descriptor is not null)
{
services.Remove(descriptor);
}
services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(_postgresContainer.GetConnectionString(), x =>
{
x.MigrationsAssembly(Assembly.GetAssembly(typeof(Program))!.FullName);
}));
});
}
public async Task InitializeAsync()
{
await _postgresContainer.StartAsync();
Db = Services.CreateScope().ServiceProvider.GetRequiredService<AppDbContext>();
await Db.Database.EnsureDeletedAsync();
// applying migrations
await Db.Database.MigrateAsync();
// initializing respawner
_connection = Db.Database.GetDbConnection();
await _connection.OpenAsync();
_respawner = await Respawner.CreateAsync(_connection, new RespawnerOptions
{
DbAdapter = DbAdapter.Postgres,
SchemasToInclude = ["public"],
WithReseed = true
});
}
public async Task DisposeAsync()
{
await _connection.CloseAsync();
await _postgresContainer.StopAsync();
await Db.DisposeAsync();
await base.DisposeAsync();
}
}
I tried to add Db property into Fixture class and use it in the test class, but DbContext isn't thread safe so can't rely on this
I forgot to mention my problem, i really need IServiceProvider since it can provide me with a new DbContext instances for each service instance i'm testing
Upvotes: 0
Views: 55