---
title: TUnit
description: Use AutoDataSource, AutoArguments, and parameter attributes with TUnit test projects.
updated: 2026-09-08
badge:
  label: Preview
  color: warning
  variant: subtle
---

[TUnit](https://github.com/thomhurst/TUnit) is a modern .NET test framework built on Microsoft.Testing.Platform. It uses data-source attributes to feed arguments into `[Test]` methods; you normally supply those values yourself (or with TUnit's built-in data sources).

**AutoFixture.TUnit** connects AutoFixture to TUnit. Attributes such as `[AutoDataSource]` and `[AutoArguments]` fill test parameters with anonymous specimens so you skip most of the arrange setup.

AutoFixture.TUnit currently targets **AutoFixture 4** (`4.18.1`) and ships as a NuGet preview.

## Prerequisites

- .NET 8+ test project (the package also supports `netstandard2.0` consumers)
- [AutoFixture](https://www.nuget.org/packages/AutoFixture/4.18.1) 4.18.1
- [TUnit](https://github.com/thomhurst/TUnit)

## Install

```xml
<PackageReference Include="AutoFixture" Version="4.18.1" />
<PackageReference Include="AutoFixture.TUnit" Version="0.1.0-preview0001" />
<PackageReference Include="TUnit" Version="1.66.8" />
```

`AutoFixture.TUnit` depends on `TUnit.Core`. Reference the full **TUnit** package in test projects for `[Test]` and assertions.

## Example scenario

You are testing `MyClass.Echo` with TUnit. The test needs an integer and a `MyClass` instance without manual arrange code. Later tests freeze collaborators, mix inline rows with generated values, or share fixture setup across tests.

## AutoDataSource

```csharp
[Test, AutoDataSource]
public async Task AutoDataSource_ProvidesTestParameters(int expectedNumber, MyClass sut)
{
    var result = sut.Echo(expectedNumber);

    await Assert.That(result).IsEqualTo(expectedNumber);
}
```

## AutoArguments

Mix explicit values with generated ones. Explicit arguments fill parameters left-to-right; AutoFixture generates the rest:

```csharp
[Test]
[AutoArguments("alpha")]
[AutoArguments("alpha", "beta")]
public async Task AutoArguments_MixesExplicitAndGeneratedValues(string first, string second)
{
    await Assert.That(first).IsEqualTo("alpha");
    await Assert.That(string.IsNullOrEmpty(second)).IsFalse();
}
```

Prefer the generic form when a single inline value must stay strongly typed — especially arrays. Non-generic `params object?[]` can expand an array into multiple cells:

```csharp
[Test, AutoArguments<int[]>([1, 2])]
public async Task AutoArguments_GenericArray_KeepsOneParameter(int[] values, MyClass sut)
{
    await Assert.That(values).IsEquivalentTo([1, 2]);
    await Assert.That(sut).IsNotNull();
}
```

## AutoMemberDataSource and AutoClassDataSource

Use `[AutoMemberDataSource]` when some values come from a static member (property, field, or method). Use `[AutoClassDataSource]` when values come from a separate provider type. AutoFixture fills any remaining parameters.

```csharp
public static IEnumerable<(int Left, int Right)> TupleRows =>
[
    (2, 3),
    (10, -4)
];

[Test, AutoMemberDataSource(nameof(TupleRows))]
public async Task AutoMemberDataSource_FillsRemainingParameters(
    int a, int b, Calculator calculator)
{
    await Assert.That(calculator.Add(a, b)).IsEqualTo(a + b);
}

[Test, AutoClassDataSource(typeof(KnownSumRows))]
public async Task AutoClassDataSource_FillsRemainingParameters(
    int a, int b, Calculator calculator)
{
    await Assert.That(calculator.Add(a, b)).IsEqualTo(a + b);
}

public class KnownSumRows : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        yield return [1, 1];
        yield return [7, 8];
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
```

Generic forms (C# 11+) avoid `typeof(...)` for the member host or provider type:

```csharp
[Test, AutoMemberDataSource<CalculatorTests>(nameof(TupleRows))]
public async Task AutoMemberDataSource_GenericHost(int a, int b, Calculator calculator)
{
    await Assert.That(calculator.Add(a, b)).IsEqualTo(a + b);
}

[Test, AutoClassDataSource<KnownSumRows>]
public async Task AutoClassDataSource_GenericProvider(int a, int b, Calculator calculator)
{
    await Assert.That(calculator.Add(a, b)).IsEqualTo(a + b);
}
```

`[AutoClassDataSource]` is **not** TUnit's `[ClassDataSource<T>]`. TUnit's attribute injects an instance of `T`; AutoFixture's attribute supplies **rows** and generates leftover arguments. An empty member or class sequence yields **no test rows**.

## Parameter attributes

Apply attributes on test parameters to customize how that parameter (and later parameters) are created.

### Frozen

Without `[Frozen]`, each parameter of the same type gets its own anonymous instance. [`[Frozen]`](/api/tunit/0-1-0-preview0001/autofixture.tunit.frozenattribute) tells AutoFixture: create this parameter once, then reuse that same instance for later requests of a matching type.

```csharp
[Test, AutoDataSource]
public async Task Frozen_SharesSameInstance([Frozen] string first, string second)
{
    await Assert.That(second).IsEqualTo(first);
}
```

Only parameters that come **after** the frozen one reuse it. Earlier parameters of the same type stay independent.

### Frozen with Matching

By default, freeze matches the **exact type** only (`Matching.ExactType`). A frozen `InMemoryOrderRepository` would not satisfy an `IOrderRepository` constructor parameter.

Use [`Matching`](/api/tunit/0-1-0-preview0001/autofixture.tunit.matching) to widen what the frozen value can satisfy:

```csharp
[Test, AutoDataSource]
public async Task Frozen_ByImplementedInterfaces_InjectsConcreteIntoInterface(
    [Frozen(Matching.ImplementedInterfaces)] InMemoryOrderRepository repository,
    OrderService sut,
    Order order)
{
    sut.PlaceOrder(order);

    await Assert.That(repository.Saved).Contains(order);
}
```

`OrderService` needs `IOrderRepository`. With `Matching.ImplementedInterfaces`, the frozen concrete repository is also used wherever that interface is requested — so `sut` and `repository` share one instance and you can assert on `repository.Saved`.

| Flag | Matches requests for… |
| --- | --- |
| `ExactType` | The same type as the parameter (default) |
| `DirectBaseType` | The parameter's immediate base type |
| `ImplementedInterfaces` | Interfaces the parameter type implements |
| `ParameterName` | A constructor/method parameter with the same name |
| `PropertyName` | A property with the same name |
| `FieldName` | A field with the same name |
| `MemberName` | Parameter, property, or field with the same name |

Combine flags with `|`, for example `Matching.ExactType | Matching.ImplementedInterfaces`.

### Modest and Greedy

When a type has several constructors, AutoFixture must pick one. For `MultiCtorProduct` that means: parameterless, name-only, or name + price.

- **`[Modest]`** — prefer the constructor with the **fewest** parameters (most modest). Here that is the parameterless constructor, so you get the hard-coded defaults `"default"` / `0m`.
- **`[Greedy]`** — prefer the constructor with the **most** parameters (greediest). Here that is `(string name, decimal price)`, so AutoFixture generates anonymous values for both.

```csharp
[Test, AutoDataSource]
public async Task ModestAttribute_UsesParameterlessConstructor([Modest] MultiCtorProduct product)
{
    await Assert.That(product.Name).IsEqualTo("default");
    await Assert.That(product.Price).IsEqualTo(0m);
}

[Test, AutoDataSource]
public async Task GreedyAttribute_UsesFullestConstructor([Greedy] MultiCtorProduct product)
{
    await Assert.That(string.IsNullOrEmpty(product.Name)).IsFalse();
    await Assert.That(product.Price).IsNotEqualTo(0m);
}
```

You can combine attributes on one parameter, for example `[Frozen][Greedy]`. See also [Behaviors](/docs/fundamentals/behaviors).

### NoAutoProperties

By default, after construction AutoFixture assigns anonymous values to writable public properties. [`[NoAutoProperties]`](/api/tunit/0-1-0-preview0001/autofixture.tunit.noautopropertiesattribute) turns that off for the parameter's type — the instance is created, but properties keep their type defaults (here `string.Empty` for `Name`).

```csharp
[Test, AutoDataSource]
public async Task NoAutoProperties_LeavesWritablePropertiesUnset([NoAutoProperties] Person person)
{
    await Assert.That(person.Name).IsEqualTo(string.Empty);
}
```

### FavorArrays, FavorLists, and FavorEnumerables

Like Modest/Greedy, these change **which constructor** is chosen when a type overloads constructors that take different collection shapes:

- **`[FavorArrays]`** — prefer a constructor that takes an array (`T[]`)
- **`[FavorLists]`** — prefer a constructor that takes `IList<T>`
- **`[FavorEnumerables]`** — prefer a constructor that takes `IEnumerable<T>`

Use them when the type exposes several collection constructors and the default choice is not the one your test needs.

### Custom parameter attribute

Subclass [`CustomizeAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.customizeattribute) and return an `ICustomization` from `GetCustomization`. AutoFixture applies it when resolving that parameter:

```csharp
using System.Reflection;
using AutoFixture;
using AutoFixture.TUnit;

public sealed class NamedAttribute(string name) : CustomizeAttribute
{
    public override ICustomization GetCustomization(ParameterInfo parameter)
    {
        ArgumentNullException.ThrowIfNull(parameter);

        return new NamedCustomization(name);
    }

    private sealed class NamedCustomization(string value) : ICustomization
    {
        public void Customize(IFixture fixture) => fixture.Inject(value);
    }
}

[Test, AutoDataSource]
public async Task CustomParameterAttribute_InjectsConfiguredValue([Named("widget")] string name)
{
    await Assert.That(name).IsEqualTo("widget");
}
```

`[Named("widget")]` injects the fixed string `"widget"` for that parameter instead of an anonymous value. Use custom attributes for team-specific rules that do not already exist as built-ins. Combine with `[Frozen]` when later parameters should reuse the same value.

## Custom AutoDataSource attribute

When tests need the same fixture setup (for example AutoMoq), define a custom attribute instead of repeating `Customize` in every test.

Add **AutoFixture.AutoMoq** `4.18.1` when the factory uses `AutoMoqCustomization`. The [AutoMoq](/docs/integrations/automoq) guide documents the same customization on AutoFixture 5 — keep AutoFixture and AutoMoq on matching major versions.

```csharp
public class AutoMoqDataSourceAttribute : AutoDataSourceAttribute
{
    public AutoMoqDataSourceAttribute()
        : base(() => new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}

[Test, AutoMoqDataSource]
public async Task CustomAutoDataSource_UsesFixtureFactory(OrderService service, Order order)
{
    await Assert.That(service).IsNotNull();

    await Assert.That(() => service.PlaceOrder(order)).ThrowsNothing();
}
```

Subclass `AutoDataSourceAttribute` and pass a factory `Func<IFixture>` to the base constructor. The factory runs once per test case and supplies the configured fixture; parameters are resolved from that fixture.

## Custom AutoArguments attribute

Subclass `AutoArgumentsAttribute` the same way — pass a fixture factory plus the inline values:

```csharp
public class AutoMoqArgumentsAttribute : AutoArgumentsAttribute
{
    public AutoMoqArgumentsAttribute(params object?[] values)
        : base(() => new Fixture().Customize(new AutoMoqCustomization()), values)
    {
    }
}

[Test]
[AutoMoqArguments(42)]
public async Task CustomAutoArguments_MixesExplicitValuesWithCustomFixture(
    int orderId,
    OrderService service,
    string productName)
{
    await Assert.That(orderId).IsEqualTo(42);
    await Assert.That(service).IsNotNull();
    await Assert.That(string.IsNullOrEmpty(productName)).IsFalse();

    await Assert.That(() => service.PlaceOrder(new Order(orderId, productName))).ThrowsNothing();
}
```

Explicit values still fill parameters left-to-right; AutoFixture fills the rest from the customized fixture.

## How it works

- **`[AutoDataSource]`** — TUnit `[Test]` methods get anonymous parameters from AutoFixture
- **`[AutoArguments(...)]`** / **`[AutoArguments<T>(...)]`** — explicit inline values fill parameters left-to-right; AutoFixture generates the rest
- **`[AutoMemberDataSource]`** / **`[AutoClassDataSource]`** — member or class rows supply some columns; AutoFixture fills the rest
- **`[Frozen]` / `[Frozen(Matching...)]`** — create once; reuse for later matching requests (exact type, interfaces, names, …)
- **`[Modest]` / `[Greedy]`** — fewest vs most constructor parameters
- **`[NoAutoProperties]`** — construct without filling writable properties
- **`[FavorArrays]` / `[FavorLists]` / `[FavorEnumerables]`** — prefer constructors that take that collection shape
- **Custom `CustomizeAttribute`** — return an `ICustomization` for that parameter
- Subclass `AutoDataSourceAttribute` or `AutoArgumentsAttribute` to share fixture setup across tests

## Next steps

- [Integrations overview](/docs/integrations)
- [xUnit.net 3](/docs/integrations/xunit3)
- [NUnit 4](/docs/integrations/nunit4)
- [AutoMoq](/docs/integrations/automoq)
- [Behaviors](/docs/fundamentals/behaviors)
- [Register, Freeze, and Inject](/docs/how-to/register-freeze-inject)
- [NuGet packages](/docs/reference/packages)
- [FAQ](/docs/reference/faq)

## API

- [AutoFixture.TUnit package](/api/tunit/0-1-0-preview0001)
- [`AutoDataSourceAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.autodatasourceattribute)
- [`AutoArgumentsAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.autoargumentsattribute)
- [`AutoMemberDataSourceAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.automemberdatasourceattribute)
- [`AutoClassDataSourceAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.autoclassdatasourceattribute)
- [`FrozenAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.frozenattribute)
- [`Matching`](/api/tunit/0-1-0-preview0001/autofixture.tunit.matching)
- [`ModestAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.modestattribute)
- [`GreedyAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.greedyattribute)
- [`NoAutoPropertiesAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.noautopropertiesattribute)
- [`FavorArraysAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.favorarraysattribute)
- [`FavorListsAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.favorlistsattribute)
- [`FavorEnumerablesAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.favorenumerablesattribute)
- [`CustomizeAttribute`](/api/tunit/0-1-0-preview0001/autofixture.tunit.customizeattribute)
