integration-test-patterns

michaellperry's avatarfrom michaellperry

Best practices for writing integration tests using Testcontainers and EF Core. Use when creating or modifying integration tests.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 11, 2026

When & Why to Use This Skill

This Claude skill provides standardized patterns and best practices for writing robust integration tests using Testcontainers and Entity Framework Core (EF Core). It focuses on managing container lifecycles, ensuring data isolation, and implementing reliable database context management to improve test accuracy and performance in .NET environments.

Use Cases

  • Case 1: Setting up containerized SQL Server environments for integration testing to ensure environment parity across development and CI/CD pipelines.
  • Case 2: Implementing the 'Fresh Context Pattern' to accurately verify database persistence and bypass EF Core's internal cache during the Assert phase.
  • Case 3: Ensuring test isolation in shared database environments by using unique tenant IDs and random data generation to prevent test collisions.
  • Case 4: Optimizing test execution speed by implementing shared database fixtures to reduce the overhead of starting and stopping containers.
nameintegration-test-patterns
descriptionBest practices for writing integration tests using Testcontainers and EF Core. Use when creating or modifying integration tests.

Integration Test Patterns

Infrastructure

DatabaseFixture

Use the DatabaseFixture to manage the SQL Server container lifecycle. This fixture is shared across tests to reduce overhead.

public class MyTests : IClassFixture<DatabaseFixture>
{
    private readonly DatabaseFixture _fixture;

    public MyTests(DatabaseFixture fixture)
    {
        _fixture = fixture;
    }
}

Context Management

Use the CreateDbContext helper pattern to create fresh contexts for Arrange and Act/Assert phases.

private static GloboTicketDbContext CreateDbContext(string connectionString, int? tenantId)
{
    var options = new DbContextOptionsBuilder<GloboTicketDbContext>()
        .UseSqlServer(connectionString, sqlOptions => sqlOptions.UseNetTopologySuite())
        .Options;

    var tenantContext = new TestTenantContext(tenantId);
    var context = new GloboTicketDbContext(options, tenantContext);
    
    context.Database.Migrate();
    
    return context;
}

Test Structure

Fresh Context Pattern

Always use a separate context for verifying data persistence to ensure EF Core didn't just return cached entities.

// Arrange
using (var setupContext = CreateDbContext(_fixture.ConnectionString, _tenantId))
{
    // ... create data ...
}

// Act & Assert
using (var context = CreateDbContext(_fixture.ConnectionString, _tenantId))
{
    // ... verify data ...
}

Isolation

Use _fixture.GenerateRandomTenantId() and Guid.NewGuid() for properties like Slugs or Names to ensure tests do not collide in the shared container.

Performance and Execution

For guidance on test parallelization, cleanup strategies, and CI/CD organization, see Performance.