Since the last lesson, the Kladde's integration tests run against SQL Server in the container, in one collection and therefore one after another. That is safe but slow, and it hides a problem: the tests share a database. As soon as two of them run at the same time or one finds the traces of another, they turn red without anything being wrong in the code. In this lesson each test gets its own data, and after that the tests may run at the same time.

Three ways of getting in each other's way

Tests that share a database almost always interfere in one of these three ways:

  • They count the whole table. A test imports two contacts and checks CountAsync() == 2. If another test that also creates contacts runs before it or at the same time, there are five.
  • They use the same keys. Two tests both create “Mara Feld” with mara.feld@example.com, or both book Wednesday at 10 a.m. The unique index rejects the second, and depending on the order, sometimes one is red, sometimes the other.
  • They rely on the order. Test B reads the contact that test A created. Started alone, B fails; xUnit promises no order, not even the one in the source code.

This is what the first way looks like. The test is green alone and red in company:

C#
// not like this: the test counts all contacts, including those of other tests
[Fact]
public async Task BadImportCountsTheWholeTable()
{
    var cancellationToken = TestContext.Current.CancellationToken;
    await using var db = database.CreateDbContext();
    await new ContactImport(db).ImportAsync(
    [
        new ContactRow("Jonas Kranich", "jonas.kranich@example.com"),
        new ContactRow("Lea Brandt", "lea.brandt@example.com"),
    ], cancellationToken);

    Assert.Equal(2, await db.Contacts.CountAsync(cancellationToken));
}

The rule that prevents all three ways: each test creates the data it needs itself, with its own keys, and checks only that data. To keep that convenient, there are two patterns.