From 674caa87b393ee3f6a3ac2e816a21483e713d2b1 Mon Sep 17 00:00:00 2001 From: Andrei Ivascu <7030530+aivascu@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:45:23 +0300 Subject: [PATCH 1/2] Add TUnit integration guide and API catalog entry. Document AutoFixture.TUnit alongside the other integrations, zero-pad sidebar order so string sort keeps TUnit last, and register the preview package for DocFX API docs. --- api-gen/packages.json | 8 + api-gen/readme.md | 147 ++++---- .../{0.overview.md => 00.overview.md} | 10 +- .../{1.xunit3.md => 01.xunit3.md} | 4 +- .../{2.automoq.md => 02.automoq.md} | 4 +- .../{4.nunit4.md => 04.nunit4.md} | 4 +- ...tonsubstitute.md => 06.autonsubstitute.md} | 4 +- ...autofakeiteasy.md => 09.autofakeiteasy.md} | 4 +- site/content/docs/5.integrations/10.tunit.md | 350 ++++++++++++++++++ site/content/docs/7.reference/1.packages.md | 1 + site/public/llms.txt | 2 + 11 files changed, 456 insertions(+), 82 deletions(-) rename site/content/docs/5.integrations/{0.overview.md => 00.overview.md} (71%) rename site/content/docs/5.integrations/{1.xunit3.md => 01.xunit3.md} (96%) rename site/content/docs/5.integrations/{2.automoq.md => 02.automoq.md} (95%) rename site/content/docs/5.integrations/{4.nunit4.md => 04.nunit4.md} (95%) rename site/content/docs/5.integrations/{6.autonsubstitute.md => 06.autonsubstitute.md} (94%) rename site/content/docs/5.integrations/{9.autofakeiteasy.md => 09.autofakeiteasy.md} (93%) create mode 100644 site/content/docs/5.integrations/10.tunit.md diff --git a/api-gen/packages.json b/api-gen/packages.json index adea775..5e9efef 100644 --- a/api-gen/packages.json +++ b/api-gen/packages.json @@ -170,6 +170,14 @@ "line": "v4", "targetFramework": "net452", "assemblyName": "AutoFixture.AutoRhinoMock" + }, + { + "id": "tunit", + "name": "AutoFixture.TUnit", + "nugetId": "AutoFixture.TUnit", + "version": "0.1.0-preview0001", + "line": "v4", + "targetFramework": "net8.0" } ] } diff --git a/api-gen/readme.md b/api-gen/readme.md index ef021f0..9e5ddd2 100644 --- a/api-gen/readme.md +++ b/api-gen/readme.md @@ -1,73 +1,74 @@ -# API markdown generator - -Uses DocFX `metadata` with `outputFormat: markdown` against NuGet package assemblies. All automation is Node.js (`api-gen/run.mjs`). - -## Prerequisites - -- [.NET SDK](https://dotnet.microsoft.com/download) (for DocFX) -- [DocFX](https://dotnet.github.io/docfx/): `dotnet tool install -g docfx` -- Node.js -- [just](https://github.com/casey/just#installation) (optional wrapper) - -On **Linux/WSL**, dotnet global tools are not always on `PATH`. Add this to `~/.bashrc`: - -```bash -export PATH="$PATH:$HOME/.dotnet/tools" -``` - -Then verify: `docfx --version` - -## Commands (from repo root) - -```bash -node api-gen/run.mjs prepare # generate + sync into site/public/ -just prepare-api # same via just -just clean-api # delete generated output and NuGet cache -``` - -Output layout after sync: - -| Path | Contents | -|------|----------| -| `site/public/api-markdown/{packageId}/{version}/` | Raw DocFX markdown (`.md`) | -| `site/public/api-meta/{packageId}/{version}/` | `toc.json`, `search.json`, `pages/{slug}.json` | -| `site/public/api-meta/routes.json` | All API routes for prerender | -| `site/public/api-catalog.json` | Package/version picker data | - -Configure packages in `api-gen/packages.json`. Each entry is one package version (same `id` groups versions in the UI). Generated routes use `/api/{packageId}/{versionSegment}/...`. - -Packages are downloaded from nuget.org into `api-gen/packages-cache/` and DocFX reads the `.dll` plus companion `.xml` documentation file from the chosen target framework folder. - -Required fields per package: - -| Field | Purpose | -|-------|---------| -| `id` | URL slug | -| `name` | Display name | -| `nugetId` | NuGet package id (defaults to `name`) | -| `version` | Pinned NuGet version | -| `line` | UI grouping (`v4` / `v5`) | -| `targetFramework` | TFM folder under `lib/` (for example `netstandard2.0`, `net8.0`, `net452`) | -| `assemblyName` | Optional when the DLL name differs from the NuGet id | - -Currently generated packages (URL slug → NuGet name): - -| Slug | NuGet package | v5 | v4 | -|------|---------------|----|----| -| `autofixture` | AutoFixture | yes | yes | -| `xunit3` | AutoFixture.Xunit3 | yes | — | -| `nunit4` | AutoFixture.NUnit4 | yes | — | -| `xunit` | AutoFixture.xUnit | — | yes | -| `xunit2` | AutoFixture.xUnit2 | — | yes | -| `nunit2` | AutoFixture.NUnit2 | — | yes | -| `nunit3` | AutoFixture.NUnit3 | — | yes | -| `automoq` | AutoFixture.AutoMoq | yes | yes | -| `autonsubstitute` | AutoFixture.AutoNSubstitute | yes | yes | -| `autofakeiteasy` | AutoFixture.AutoFakeItEasy | yes | yes | -| `seedextensions` | AutoFixture.SeedExtensions | yes | yes | -| `idioms` | AutoFixture.Idioms | yes | yes | -| `idioms-fscheck` | AutoFixture.Idioms.FsCheck | — | yes | -| `autofoq` | AutoFixture.AutoFoq | — | yes | -| `autorhinomocks` | AutoFixture.AutoRhinoMocks | — | yes | - -v5 is pinned to `5.0.0-rc.1`; v4 is pinned to `4.18.1`. +# API markdown generator + +Uses DocFX `metadata` with `outputFormat: markdown` against NuGet package assemblies. All automation is Node.js (`api-gen/run.mjs`). + +## Prerequisites + +- [.NET SDK](https://dotnet.microsoft.com/download) (for DocFX) +- [DocFX](https://dotnet.github.io/docfx/): `dotnet tool install -g docfx` +- Node.js +- [just](https://github.com/casey/just#installation) (optional wrapper) + +On **Linux/WSL**, dotnet global tools are not always on `PATH`. Add this to `~/.bashrc`: + +```bash +export PATH="$PATH:$HOME/.dotnet/tools" +``` + +Then verify: `docfx --version` + +## Commands (from repo root) + +```bash +node api-gen/run.mjs prepare # generate + sync into site/public/ +just prepare-api # same via just +just clean-api # delete generated output and NuGet cache +``` + +Output layout after sync: + +| Path | Contents | +|------|----------| +| `site/public/api-markdown/{packageId}/{version}/` | Raw DocFX markdown (`.md`) | +| `site/public/api-meta/{packageId}/{version}/` | `toc.json`, `search.json`, `pages/{slug}.json` | +| `site/public/api-meta/routes.json` | All API routes for prerender | +| `site/public/api-catalog.json` | Package/version picker data | + +Configure packages in `api-gen/packages.json`. Each entry is one package version (same `id` groups versions in the UI). Generated routes use `/api/{packageId}/{versionSegment}/...`. + +Packages are downloaded from nuget.org into `api-gen/packages-cache/` and DocFX reads the `.dll` plus companion `.xml` documentation file from the chosen target framework folder. + +Required fields per package: + +| Field | Purpose | +|-------|---------| +| `id` | URL slug | +| `name` | Display name | +| `nugetId` | NuGet package id (defaults to `name`) | +| `version` | Pinned NuGet version | +| `line` | UI grouping (`v4` / `v5`) | +| `targetFramework` | TFM folder under `lib/` (for example `netstandard2.0`, `net8.0`, `net452`) | +| `assemblyName` | Optional when the DLL name differs from the NuGet id | + +Currently generated packages (URL slug → NuGet name): + +| Slug | NuGet package | v5 | v4 | +|------|---------------|----|----| +| `autofixture` | AutoFixture | yes | yes | +| `xunit3` | AutoFixture.Xunit3 | yes | — | +| `nunit4` | AutoFixture.NUnit4 | yes | — | +| `xunit` | AutoFixture.xUnit | — | yes | +| `xunit2` | AutoFixture.xUnit2 | — | yes | +| `nunit2` | AutoFixture.NUnit2 | — | yes | +| `nunit3` | AutoFixture.NUnit3 | — | yes | +| `automoq` | AutoFixture.AutoMoq | yes | yes | +| `autonsubstitute` | AutoFixture.AutoNSubstitute | yes | yes | +| `autofakeiteasy` | AutoFixture.AutoFakeItEasy | yes | yes | +| `seedextensions` | AutoFixture.SeedExtensions | yes | yes | +| `idioms` | AutoFixture.Idioms | yes | yes | +| `idioms-fscheck` | AutoFixture.Idioms.FsCheck | — | yes | +| `autofoq` | AutoFixture.AutoFoq | — | yes | +| `autorhinomocks` | AutoFixture.AutoRhinoMocks | — | yes | +| `tunit` | AutoFixture.TUnit | — | yes (`0.1.0-preview0001`) | + +v5 is pinned to `5.0.0-rc.1`; v4 is pinned to `4.18.1` (except AutoFixture.TUnit, which is on its own preview version). diff --git a/site/content/docs/5.integrations/0.overview.md b/site/content/docs/5.integrations/00.overview.md similarity index 71% rename from site/content/docs/5.integrations/0.overview.md rename to site/content/docs/5.integrations/00.overview.md index e6a0cc7..578dd94 100644 --- a/site/content/docs/5.integrations/0.overview.md +++ b/site/content/docs/5.integrations/00.overview.md @@ -1,6 +1,6 @@ --- title: Overview -description: Third-party test frameworks and libraries that AutoFixture integrates with on v5. +description: Third-party test frameworks and libraries that AutoFixture integrates with. --- AutoFixture ships extension packages that connect to tools you already use in .NET test projects. Each guide below covers the third-party library, what AutoFixture adds, and how to install both sides. @@ -9,10 +9,11 @@ Pick the test framework you use, then add a mocking library if your tests need s ## Test frameworks -These libraries run your tests. AutoFixture extensions add `[AutoData]`, `[InlineAutoData]`, and related attributes so method parameters become anonymous specimens. +These libraries run your tests. AutoFixture extensions add data attributes so method parameters become anonymous specimens (`[AutoData]` / `[InlineAutoData]` on xUnit and NUnit; `[AutoDataSource]` / `[AutoArguments]` on TUnit). -- [xUnit.net 3](/docs/integrations/xunit3) -- [NUnit 4](/docs/integrations/nunit4) +- [xUnit.net 3](/docs/integrations/xunit3) — AutoFixture 5 +- [NUnit 4](/docs/integrations/nunit4) — AutoFixture 5 +- [TUnit](/docs/integrations/tunit) — AutoFixture 4 (preview) ## Mocking libraries @@ -26,6 +27,7 @@ These libraries create test doubles. AutoFixture extensions register them as res - [Custom AutoData attribute](/docs/integrations/xunit3#custom-autodata-attribute) — share fixture setup (for example AutoMoq) across xUnit.net 3 theories - [NUnit 4 custom attributes](/docs/integrations/nunit4#custom-autodata-attribute) — the same pattern for NUnit 4 tests +- [TUnit custom AutoDataSource](/docs/integrations/tunit#custom-autodatasource-attribute) — the same pattern for TUnit tests - [AutoFixture integration packages](/docs/reference/packages) — NuGet packages that wrap the libraries above - [v4 to v5 migration](/docs/reference/v4-to-v5-migration) — map older xUnit.net and NUnit integration packages to v5 - [FAQ](/docs/reference/faq) — interfaces, Freeze, AutoData, and other common failures diff --git a/site/content/docs/5.integrations/1.xunit3.md b/site/content/docs/5.integrations/01.xunit3.md similarity index 96% rename from site/content/docs/5.integrations/1.xunit3.md rename to site/content/docs/5.integrations/01.xunit3.md index fff24cf..7954a73 100644 --- a/site/content/docs/5.integrations/1.xunit3.md +++ b/site/content/docs/5.integrations/01.xunit3.md @@ -3,7 +3,9 @@ title: xUnit.net 3 description: Use AutoData, InlineAutoData, and parameter attributes with xUnit.net 3 test projects. --- -`[AutoData]` turns test method parameters into anonymous specimens so you skip manual arrange setup. +[xUnit.net](https://xunit.net/) is a popular .NET unit testing framework. Theories and facts take parameters; you normally supply those values yourself (or with `[InlineData]` / `[MemberData]`). + +**AutoFixture.Xunit3** connects AutoFixture to xUnit.net 3. Attributes such as `[AutoData]` and `[InlineAutoData]` fill theory parameters with anonymous specimens so you skip most of the arrange setup. ## Prerequisites diff --git a/site/content/docs/5.integrations/2.automoq.md b/site/content/docs/5.integrations/02.automoq.md similarity index 95% rename from site/content/docs/5.integrations/2.automoq.md rename to site/content/docs/5.integrations/02.automoq.md index 381a91c..0e27760 100644 --- a/site/content/docs/5.integrations/2.automoq.md +++ b/site/content/docs/5.integrations/02.automoq.md @@ -3,7 +3,9 @@ title: AutoMoq description: Moq integration — let AutoFixture create Moq mocks for interfaces and abstract types automatically. --- -AutoMoq turns interface and abstract dependencies into Moq mocks when AutoFixture builds object graphs. +[Moq](https://github.com/moq/moq) is a .NET mocking library. You create `Mock` instances for interfaces and abstract types, then set up return values and verify calls. + +**AutoFixture.AutoMoq** plugs Moq into AutoFixture. When AutoFixture builds an object graph and needs an interface or abstract dependency, AutoMoq supplies a Moq mock instead of failing — so you can `Freeze` mocks and assert on them with less manual setup. ## Prerequisites diff --git a/site/content/docs/5.integrations/4.nunit4.md b/site/content/docs/5.integrations/04.nunit4.md similarity index 95% rename from site/content/docs/5.integrations/4.nunit4.md rename to site/content/docs/5.integrations/04.nunit4.md index bfddca4..178ac21 100644 --- a/site/content/docs/5.integrations/4.nunit4.md +++ b/site/content/docs/5.integrations/04.nunit4.md @@ -3,7 +3,9 @@ title: NUnit 4 description: Use AutoData, InlineAutoData, and parameter attributes with NUnit 4 test projects. --- -`[AutoData]` turns test method parameters into anonymous specimens so you skip manual arrange setup. Works like [xUnit.net 3](/docs/integrations/xunit3), but uses NUnit's `[Test]` attribute. +[NUnit](https://nunit.org/) is a long-standing .NET unit testing framework. Tests can take parameters; you normally supply those values yourself (or with `[TestCase]` / `[TestCaseSource]`). + +**AutoFixture.NUnit4** connects AutoFixture to NUnit 4. Attributes such as `[AutoData]` and `[InlineAutoData]` fill test parameters with anonymous specimens so you skip most of the arrange setup. The pattern matches [xUnit.net 3](/docs/integrations/xunit3), but uses NUnit's `[Test]` attribute. ## Prerequisites diff --git a/site/content/docs/5.integrations/6.autonsubstitute.md b/site/content/docs/5.integrations/06.autonsubstitute.md similarity index 94% rename from site/content/docs/5.integrations/6.autonsubstitute.md rename to site/content/docs/5.integrations/06.autonsubstitute.md index eb9a4bb..8973792 100644 --- a/site/content/docs/5.integrations/6.autonsubstitute.md +++ b/site/content/docs/5.integrations/06.autonsubstitute.md @@ -3,7 +3,9 @@ title: AutoNSubstitute description: NSubstitute integration — create substitutes automatically with AutoNSubstituteCustomization. --- -AutoNSubstitute turns interface and abstract dependencies into NSubstitute substitutes when AutoFixture builds object graphs. +[NSubstitute](https://nsubstitute.github.io/) is a .NET mocking library with a substitute-focused API. You create substitutes for interfaces and abstract types, then configure returns and assert received calls. + +**AutoFixture.AutoNSubstitute** plugs NSubstitute into AutoFixture. When AutoFixture builds an object graph and needs an interface or abstract dependency, AutoNSubstitute supplies a substitute instead of failing — so collaborators resolve automatically and you can assert on them with less manual setup. ## Prerequisites diff --git a/site/content/docs/5.integrations/9.autofakeiteasy.md b/site/content/docs/5.integrations/09.autofakeiteasy.md similarity index 93% rename from site/content/docs/5.integrations/9.autofakeiteasy.md rename to site/content/docs/5.integrations/09.autofakeiteasy.md index 1f67926..9de5598 100644 --- a/site/content/docs/5.integrations/9.autofakeiteasy.md +++ b/site/content/docs/5.integrations/09.autofakeiteasy.md @@ -3,7 +3,9 @@ title: AutoFakeItEasy description: FakeItEasy integration — use fakes with AutoFixture.AutoFakeItEasy on v5. --- -AutoFakeItEasy turns interface and abstract dependencies into FakeItEasy fakes when AutoFixture builds object graphs. +[FakeItEasy](https://fakeiteasy.github.io/) is a .NET mocking library. You create fakes for interfaces and abstract types, then configure behavior and assert calls. + +**AutoFixture.AutoFakeItEasy** plugs FakeItEasy into AutoFixture. When AutoFixture builds an object graph and needs an interface or abstract dependency, AutoFakeItEasy supplies a fake instead of failing — so collaborators resolve automatically and you can assert on them with less manual setup. ## Prerequisites diff --git a/site/content/docs/5.integrations/10.tunit.md b/site/content/docs/5.integrations/10.tunit.md new file mode 100644 index 0000000..4c36605 --- /dev/null +++ b/site/content/docs/5.integrations/10.tunit.md @@ -0,0 +1,350 @@ +--- +title: TUnit +description: Use AutoDataSource, AutoArguments, and parameter attributes with TUnit test projects. +--- + +[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 + + + +``` + +`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([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 +{ + public IEnumerator 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(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] +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]`. 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` +- **`[FavorEnumerables]`** — prefer a constructor that takes `IEnumerable` + +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` 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(...)]`** — 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) diff --git a/site/content/docs/7.reference/1.packages.md b/site/content/docs/7.reference/1.packages.md index 8a65d13..c081c4d 100644 --- a/site/content/docs/7.reference/1.packages.md +++ b/site/content/docs/7.reference/1.packages.md @@ -35,6 +35,7 @@ New projects should use **v5** (`5.0.0-rc.1`). v4 packages remain available for | AutoFixture.Idioms.FsCheck | [AutoFixture.Idioms.FsCheck 4.18.1](https://www.nuget.org/packages/AutoFixture.Idioms.FsCheck/4.18.1) | [/api/idioms-fscheck/4-18-1](/api/idioms-fscheck/4-18-1) | | AutoFixture.AutoFoq | [AutoFixture.AutoFoq 4.18.1](https://www.nuget.org/packages/AutoFixture.AutoFoq/4.18.1) | [/api/autofoq/4-18-1](/api/autofoq/4-18-1) | | AutoFixture.AutoRhinoMocks | [AutoFixture.AutoRhinoMocks 4.18.1](https://www.nuget.org/packages/AutoFixture.AutoRhinoMocks/4.18.1) | [/api/autorhinomocks/4-18-1](/api/autorhinomocks/4-18-1) | +| AutoFixture.TUnit | [AutoFixture.TUnit 0.1.0-preview0001](https://www.nuget.org/packages/AutoFixture.TUnit/0.1.0-preview0001) | [/api/tunit/0-1-0-preview0001](/api/tunit/0-1-0-preview0001) | See [v4 to v5 migration](/docs/reference/v4-to-v5-migration) when upgrading. diff --git a/site/public/llms.txt b/site/public/llms.txt index ee2ab78..31b25fa 100644 --- a/site/public/llms.txt +++ b/site/public/llms.txt @@ -24,7 +24,9 @@ Guides live under `/docs/{section}/{page}`. - https://autofixture.com/docs/how-to/collections - https://autofixture.com/docs/integrations/overview - https://autofixture.com/docs/integrations/xunit3 +- https://autofixture.com/docs/integrations/nunit4 - https://autofixture.com/docs/integrations/automoq +- https://autofixture.com/docs/integrations/tunit - https://autofixture.com/docs/advanced/specimen-pipeline - https://autofixture.com/docs/reference/packages - https://autofixture.com/docs/reference/v4-to-v5-migration From ff1be604c9ce69c6e16ac6eae587028a34d01118 Mon Sep 17 00:00:00 2001 From: Andrei Ivascu <7030530+aivascu@users.noreply.github.com> Date: Tue, 8 Sep 2026 00:32:19 +0300 Subject: [PATCH 2/2] Add explicit sidebar badges for docs articles. Wire frontmatter badge into the docs nav with New/Updated/Preview presets, and mark the TUnit guide as Preview. --- site/app/app.vue | 11 ++-- site/app/utils/docsNavigationBadge.ts | 66 ++++++++++++++++++++ site/content.config.ts | 9 +++ site/content/docs/5.integrations/10.tunit.md | 4 ++ site/readme.md | 34 +++++++++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 site/app/utils/docsNavigationBadge.ts diff --git a/site/app/app.vue b/site/app/app.vue index 9301c2e..53564f2 100644 --- a/site/app/app.vue +++ b/site/app/app.vue @@ -1,20 +1,21 @@