In this lesson, you will learn how to use Testcontainers to spin up ephemeral, real-world database instances that ensure your EF Core models behave exactly as they would in production.
When you use an in-memory database provider for tests, you lose the ability to verify database-specific features—like complex SQL functions, check constraints, or specific collation settings—because those features simply don't exist in the memory provider. To truly validate your DbContext configuration, you need an integration test that runs against a real database engine.
The Testcontainers library solves this by managing a Docker container for you. It starts the database before your test suite runs and destroys it once finished.
Practical Implementation
To set this up, you integrate it with your test project's lifecycle. Here is a simplified example of how you might initialize a SQL Server container for your integration tests:
public class UserIntegrationTests : IAsyncLifetime
{
private readonly MsSqlContainer _container = new MsSqlBuilder().Build();
public async Task InitializeAsync() => await _container.StartAsync();
[Fact]
public async Task Verify_Database_Specific_Feature()
{
var options = new DbContextOptionsBuilder<MyDbContext>()
.UseSqlServer(_container.GetConnectionString())
.Options;
using var context = new MyDbContext(options);
// Ensure the schema is created in the container
await context.Database.EnsureCreatedAsync();
// Perform your test logic here
var result = await context.Users.AnyAsync();
Assert.False(result);
}
public async Task DisposeAsync() => await _container.DisposeAsync();
}
By pointing your DbContext to the GetConnectionString() provided by the container, your code interacts with a genuine SQL Server instance. If you have configured custom value converters or specific identity column behaviors, this setup will catch any runtime discrepancies that an in-memory provider would silently ignore. This approach turns your integration tests into a high-fidelity mirror of your production environment, providing confidence that your migrations and model configurations are perfectly aligned.
Key Takeaway: Use Testcontainers to run your integration tests against a real database engine to validate that your EF Core model behaves correctly under production-like conditions.