Skip to main content

Choosing a Data Approach

TUnit offers several ways to provide data to your tests. Use this guide to pick the right one.

Decision Table

ScenarioApproachPage
Fixed inline values[Arguments(...)]Arguments
Data from a method[MethodDataSource]Method Data Sources
Shared object with lifecycle[ClassDataSource<T>]Class Data Source
Reusable data rows[TestDataRow<T>]Test Data Row
All parameter combinations[MatrixDataSource]Matrix Tests
Multiple sources on one methodCombined attributesCombined Data Sources
Hierarchical injectionNested propertiesNested Data Sources
Custom generic attributes[GenericArguments<T>]Generic Attributes

Quick Examples

Inline arguments

[Test]
[Arguments(1, 2, 3)]
[Arguments(0, 0, 0)]
public async Task Add_ReturnsSum(int a, int b, int expected)
{
await Assert.That(a + b).IsEqualTo(expected);
}

Method data source

[Test]
[MethodDataSource(nameof(GetCases))]
public async Task MyTest(string input)
{
await Assert.That(input).IsNotEmpty();
}

public static IEnumerable<string> GetCases() => ["hello", "world"];

Class data source (shared fixture)

[ClassDataSource<DatabaseFixture>(Shared = SharedType.PerTestSession)]
public class MyTests(DatabaseFixture db)
{
[Test]
public async Task QueryWorks()
{
var result = await db.QueryAsync("SELECT 1");
await Assert.That(result).IsNotNull();
}
}

Matrix (combinatorial)

[Test]
[MatrixDataSource]
public async Task Multiply(
[Matrix(2, 3)] int a,
[Matrix(4, 5)] int b)
{
await Assert.That(a * b).IsGreaterThan(0);
}
// Generates: (2,4), (2,5), (3,4), (3,5)

Quick Rules

  • [Arguments] is the simplest — use it when values are known at compile time.
  • [MethodDataSource] is best for computed or complex data.
  • [ClassDataSource<T>] manages object lifecycles (initialization, disposal, sharing across tests).
  • [MatrixDataSource] generates the Cartesian product of all [Matrix] parameter values.
  • Attributes can be combined on a single method — see Combined Data Sources.