© 2026 Hedgehog Software, LLC

TwitterGitHubDiscord
More
CommunitiesDocsAboutTermsPrivacy
Search
Star
Setup for Free
C#C
C#•5mo ago•
125 replies
Canyon

How can I improve my TestContainers with EF tests?

Hi, all:

I've been trying to figure out my favorite way to implement test containers with Entity Framework contexts. I was running into an issue where my tests would persist their database changes between each testcase. To remedy this, I created a transactional test scope that rollsback the changes after each testcase.

For this implementation, I have three files:
1)
TestFactory.cs
TestFactory.cs
: Implements an
IAsyncLifetime
IAsyncLifetime
which my test test classes inherit from, e.x.
public class GuildSettingsRepositoryTests(TestFactory factory) : IClassFixture<TestFactory>
public class GuildSettingsRepositoryTests(TestFactory factory) : IClassFixture<TestFactory>
. It contains the
PostgreSqlContainer
PostgreSqlContainer
, an
IHost
IHost
, and offers a
CreateTransactionalScopeAsync
CreateTransactionalScopeAsync
method my testcases call.
2)
TransactionalTestScope.cs
TransactionalTestScope.cs
: Implements an
IAsyncLifetime
IAsyncLifetime
which rolls back transactions at the end of the scope. Exposes
GetRequiredService<T>
GetRequiredService<T>
which testcases call to retreive the testable service.
3)
GuildSettingsRepositoryTests.cs
GuildSettingsRepositoryTests.cs
: Test class with the previously mentioned definition. Here is a sample of a testcase implementation:
    [Fact]
    public async Task GetByGuildIdAsync_WithNonExistentGuildId_ShouldReturnNull()
    {
        await using var scope = await _factory.CreateTransactionalScopeAsync();
        var guildStorage = scope.GetRequiredService<IGuildSettingsStorage>();
        const long nonExistentGuildId = 999999999999999999L;

        var result = await guildStorage.GetByGuildIdAsync(nonExistentGuildId);

        Assert.Null(result);
    }
    [Fact]
    public async Task GetByGuildIdAsync_WithNonExistentGuildId_ShouldReturnNull()
    {
        await using var scope = await _factory.CreateTransactionalScopeAsync();
        var guildStorage = scope.GetRequiredService<IGuildSettingsStorage>();
        const long nonExistentGuildId = 999999999999999999L;

        var result = await guildStorage.GetByGuildIdAsync(nonExistentGuildId);

        Assert.Null(result);
    }


Issue

This works, but calling
CreateTransactionalScopeAsync
CreateTransactionalScopeAsync
and
GetRequiredService
GetRequiredService
each testcase seems redundant and, frankly, incorrect. How can I simplify my testcase boilerplate code or prevent my testcase context updates from persisting between tests?
C# banner
C#Join
We are a programming server aimed at coders discussing everything related to C# (CSharp) and .NET.
61,871Members
Resources

Similar Threads

Was this page helpful?
Recent Announcements
Next page

Similar Threads

Testcontainers in integration tests vs BackgroundService
C#CC# / help
3y ago
my docker testcontainers crash, so my integration tests fail marvelously
C#CC# / help
2w ago
✅ how can i improve this code ?
C#CC# / help
2y ago
✅ How can I improve this code?
C#CC# / help
4y ago