Skip to content

How Do I Use Profiles?

Define one

public sealed class ApplicationTestProfile : ICompositionProfile
{
    public void Configure(CompositionBuilder builder) =>
        builder
            .UseNSubstitute()
            .UseBogus()
            .Register<IClock>(_ => new FakeClock());
}

Apply it programmatically

var composer = Composer.Create(builder => builder.AddProfile<ApplicationTestProfile>());

Apply it to a composed xUnit theory

[Theory]
[Compose<ApplicationTestProfile>]
public void ComposesTheProfileConfiguredValue(NotificationSettings settings) { }

TProfile must implement ICompositionProfile and have a public parameterless constructor — [Compose<TProfile>] enforces this at compile time via a generic constraint.

Combining more than one profile

var composer = Composer.Create(builder => builder
    .AddProfile<DomainProfile>()
    .AddProfile<InfrastructureProfile>());

Profiles apply in the order added. Build up project-wide configuration from a few small, focused profiles rather than one large one — it's easier to reuse a DomainProfile on its own in a test that doesn't need InfrastructureProfile's configuration.

Applying an already-built instance instead of a type

builder.AddProfile(new ApplicationTestProfile());

Use this over AddProfile<TProfile>() only when the profile itself needs constructor arguments — most profiles don't, and AddProfile<TProfile>() is the more common form.

Common mistakes

  • A profile that applies itself again while already applying (directly, or through a nested profile) — this is a cycle, raised immediately as CompositionConfigurationException, not a silently-ignored no-op.
  • Putting per-test assertions or mutable state inside a profile — a profile is pure Composer configuration, applied once, synchronously.

Next