xUnit test lifecycle in C#: constructor setup, IDisposable teardown, class and collection fixtures

xUnit Testing & CI/CD in .NET November 13, 2026 csharp

xUnit creates a new instance of the test class for every test.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// ======================================================================
// Q: How does the xUnit test lifecycle work? Setup, teardown and fixtures?
//
// xUnit creates a new instance of the test class for every test. There is no
// [SetUp] / [TearDown] as in NUnit / MSTest:
// - Per-test setup: the constructor in xUnit; [SetUp] / [TestInitialize] in
//   NUnit / MSTest.
// - Per-test cleanup: IDisposable / IAsyncLifetime in xUnit; [TearDown] /
//   [TestCleanup] in NUnit / MSTest.
// - Shared by all tests of a class: IClassFixture<T> in xUnit; [OneTimeSetUp] /
//   [ClassInitialize] in NUnit / MSTest.
// - Shared by many classes: ICollectionFixture<T> + [Collection] in xUnit;
//   [SetUpFixture] / [AssemblyInitialize] in NUnit / MSTest.
// - Parallelism: collections run in parallel, tests within one collection run
//   sequentially. By default every test class is its own collection. Tests that
//   share a database go in the same collection.
// - xUnit v3 (package xunit.v3): test projects are executables, with
//   TestContext.Current.CancellationToken, dynamic Assert.Skip, and
//   IAsyncLifetime using ValueTask.
// ======================================================================

// Expensive resource (PostgreSQL container), created once for all tests in the collection
public class PostgresFixture : IAsyncLifetime
{
    private readonly PostgreSqlContainer _db = new PostgreSqlBuilder().Build();
    public string ConnectionString => _db.GetConnectionString();

    public Task InitializeAsync() => _db.StartAsync();            // v3: ValueTask
    public Task DisposeAsync() => _db.DisposeAsync().AsTask();
}

[CollectionDefinition("db")]
public class DbCollection : ICollectionFixture<PostgresFixture>;

[Collection("db")]
public class OrderRepositoryTests(PostgresFixture db)    // injected by xUnit
{
    [Fact]
    public async Task Saves_and_loads_order() { /* uses db.ConnectionString */ }
}