Installation¶
Which packages to add¶
The common case is a test project that composes plain object graphs and composed test method parameters/theories. That's two packages — Compono plus whichever test-framework integration matches your test host:
dotnet add package Compono
dotnet add package Compono.XunitV3
# or, for TUnit:
dotnet add package Compono.TUnit
# or, for MSTest (MSTest.TestFramework 4.0.0+ - see the Compono.MSTest Package Guide):
dotnet add package Compono.MSTest
# or, for NUnit (NUnit 3.14.0+ - see the Compono.NUnit Package Guide):
dotnet add package Compono.NUnit
If your xUnit v3 test project publishes with PublishAot=true (Native AOT), install Compono.XunitV3.Aot and xUnit's own xunit.v3.aot.mtp-v2 host instead of Compono.XunitV3/xunit.v3.mtp-v2 — the two families are mutually exclusive in the same project (xUnit v3's reflection-mode and Native-AOT-mode package families can't be referenced together, a hard CS0433 conflict). If you're migrating an existing reflection-mode project, remove xunit.v3.mtp-v2 too — leaving it installed alongside xunit.v3.aot.mtp-v2 reintroduces the same CS0433 conflict. See the Compono.XunitV3.Aot Package Guide for the decision table and Phase 1 scope:
dotnet add package Compono
dotnet add package Compono.XunitV3.Aot
dotnet add package xunit.v3.aot.mtp-v2
This tutorial's assertions (.Should(), throughout this site's own examples) come from AwesomeAssertions, not Compono itself — add it too if your project doesn't already reference an assertion library:
Add the rest of the ecosystem as your tests need it:
dotnet add package Compono.NSubstitute # automatic substitute composition
dotnet add package Compono.Bogus # semantic fake data (names, emails, ...)
dotnet add package Compono.DependencyInjection # row.AsServiceProvider() bridge
dotnet add package Compono.Http # TestHttpHandler for HttpClient tests
Every package targets net8.0/net9.0/net10.0/net11.0 and has a stable release, except Compono.XunitV3.Aot (net9.0/net10.0/net11.0 only — matching xUnit v3's own Native AOT floor). A plain dotnet add package still picks up the right version with no extra flag. See Package Guides for what each package is for and when to add it.
Minimum .NET SDK version¶
Building a net8.0 project against Compono needs .NET SDK 8.0.400 or later — not just any SDK that can target net8.0. Compono's embedded source generator (below) is a Roslyn analyzer, and Roslyn refuses to load an analyzer built against a newer compiler than the host SDK's own (silently — a build warning, CS9057, not an error — so the generator just stops running instead of failing loudly). An SDK older than 8.0.400 (i.e. any 8.0.1xx/8.0.2xx/8.0.3xx feature band) bundles a compiler older than what Compono requires and hits exactly that. net9.0, net10.0, and net11.0 have no equivalent minimum beyond "the SDK that ships that TFM" — every released SDK for those already bundles a new enough compiler. See ADR-0003 Amendment 1 for the full account.
No other setup required¶
Compono embeds its source generator as a Roslyn analyzer inside its own package (analyzers/dotnet/cs) — adding the Compono PackageReference is the only step needed to enable ordinary composition-plan generation. There's no separate generator package to add, no nuget.config entry beyond your normal NuGet feed, and no MSBuild property required to opt in to that.
Compono.TestDoubles is the one exception: it needs an explicit <ComponoGeneratedTestDoubles>true</ComponoGeneratedTestDoubles> MSBuild property set in your project in addition to the package reference — see Compono.TestDoubles.
If your test project doesn't already reference an xUnit v3 (or TUnit, or MSTest, or NUnit) test host, Compono.XunitV3 (or Compono.TUnit, or Compono.MSTest, or Compono.NUnit) doesn't add one for you — each integrates with an existing test project, it doesn't create one.
Verify the install¶
A minimal smoke check once the packages are added:
using Compono;
var composer = Composer.Create();
var value = composer.Create<InstallationCheck>();
public sealed class InstallationCheck;
Use a plain user-defined type here, not a built-in one like int — a built-in type is satisfied by Compono's own built-in value provider without ever reaching generated construction, so it would compile and run even if the source generator/analyzer wasn't actually wired up. A custom type like InstallationCheck only composes successfully through a real generator-produced construction plan, so this check genuinely exercises the generator, not just the core package.
If this compiles and runs, the source generator is wired up correctly. Next, write your first composed theory.