C#C
C#3mo ago
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: Implements an IAsyncLifetime which my test test classes inherit from, e.x. public class GuildSettingsRepositoryTests(TestFactory factory) : IClassFixture<TestFactory>. It contains the PostgreSqlContainer, an IHost, and offers a CreateTransactionalScopeAsync method my testcases call.
2) TransactionalTestScope.cs: Implements an IAsyncLifetime which rolls back transactions at the end of the scope. Exposes GetRequiredService<T> which testcases call to retreive the testable service.
3) 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);
    }


Issue

This works, but calling CreateTransactionalScopeAsync and 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?
Was this page helpful?