Getting Started¶
Compono composes complete test environments — object graphs, shared dependencies, test doubles, and semantic fake data — from a source-generated composition plan, instead of building each dependency by hand or relying on runtime reflection to invent one.
What "composition" means here¶
Most .NET test helpers focus on object generation: given a type, produce an instance of it, usually by reflecting over its constructor and filling in plausible values. Compono starts from a different question: what does this test need — an object graph, a couple of test doubles, a shared value reused across several parameters, some semantically-realistic data — and how do all of those pieces fit together into one deterministic result?
A Composer is built once per test (or once per profile, reused across tests) from a declarative configuration: registrations, type/member rules, profiles, and provider extensions like UseNSubstitute()/UseBogus(). Compono's source generator doesn't read that configuration directly — at compile time, from each composed type's own shape (constructor, required members), it emits a structural construction plan; that plan runs at runtime and is that runtime execution which consults your configuration (registrations, rules, providers) for each value it needs. There's no reflection-based fallback in the default path, so what actually runs in your test is regular, debuggable, AOT-friendly C#, not a runtime specimen builder walking your type via Activator.CreateInstance.
var composer = Composer.Create(builder =>
{
builder.UseNSubstitute();
builder.UseBogus();
});
var customer = composer.Create<Customer>();
How this differs from AutoFixture or hand-written setup¶
- Hand-written setup — you write every
new Customer(...)call, everySubstitute.For<IRepository>(), every fakeDateTimeOffset, by hand, in every test that needs one. Explicit, but repetitive, and it's easy for test setups to drift out of sync with the type they're building. - AutoFixture — a runtime specimen engine invents values reflectively, which is fast to start with but can produce recursion/omission surprises on cyclic or ambiguous graphs, and gives you a customization API layered on top of that reflective core. See the AutoFixture migration guide if that's your starting point.
- Compono — you declare configuration once (registrations, rules, profiles), Compono's generator turns that into real construction code at compile time, and a failed composition reports a readable path and a reproducible seed (see Determinism and Seeding) instead of a generic reflection stack trace.
None of this requires giving up AutoFixture wholesale on day one — Compono is adopted incrementally, one test class or profile at a time.
Next¶
- Never touched Compono before? Start with Installation, then Your First Composed Theory.
- Want a curated path for your specific situation (migrating from AutoFixture, already using xUnit, etc.)? See Learning Paths.
- Already through the basics? Next Steps branches out to Concepts, How-to Guides, and the Cookbook.