We have ~150 integration tests that run in parallel. To ensure they are isolated, we create a fresh database each time. To create the database we call DatabaseContext.Database.MigrateAsync()
.
Unfortunately with each additional migration the time to set-up the database increases.
Alternatives I've tried that haven't reduced the total time:
EnsureCreated
.bacpac
fileThe only success I've had is to delete all the existing migrations and create a single migration in its place. This reduces the total test time significantly - by up to 50%. This feels like a hack though and I don't want to add some additional recurring maintenance step.
What's the fastest way of creating a fresh database for tests?
I've found a simple way to initialise the database without making a call per migration:
private readonly WebApplicationFactory<Program> _factory;
public async Task InitializeAsync()
{
await using AsyncServiceScope scope = _factory.Services.CreateAsyncScope();
SampleDbContext dbContext = scope.ServiceProvider.GetRequiredService<SampleDbContext>();
// this is using types normally hidden to application code
IRelationalDatabaseCreator databaseCreator = dbContext.Database.GetService<IRelationalDatabaseCreator>();
// needed for idempotency if retrying this method due to transient errors
await databaseCreator.EnsureDeletedAsync();
// creates database without schema
await databaseCreator.CreateAsync();
// script is not idempotent nor executed in a transaction
string script = dbContext.Database.GenerateCreateScript().Replace("GO", "");
await dbContext.Database.ExecuteSqlRawAsync(script);
}
Things that could be improved: