TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Eventuous/eventuous/llms.txt
Use this file to discover all available pages before exploring further.
Eventuous.Testing package provides AggregateSpec<TAggregate, TState> — a base class that lets you unit-test your aggregate domain logic in complete isolation, with no event store or infrastructure required. You express each test scenario in the familiar Given/When/Then pattern: pre-load prior events with GivenEvents, call your domain method in When, then verify the resulting emitted events with Emitted or inspect aggregate state through Then.
NuGet package
AggregateSpec<TAggregate, TState>
Constructor parameter
| Parameter | Description |
|---|---|
registry | Optional AggregateFactoryRegistry. When omitted, AggregateFactoryRegistry.Instance (the global registry) is used. |
GivenEvents() — prior event history
When is called. The default implementation returns an empty array, representing a brand-new aggregate. Events are loaded via Aggregate.Load, so every On<TEvent> handler in your State class fires exactly as it would in production.
When(TAggregate aggregate) — the action under test
aggregate instance has already been hydrated from GivenEvents() when this method is called.
CreateInstance() — aggregate factory
Then() to construct a fresh aggregate instance. Override this when your aggregate requires constructor arguments that the factory registry cannot supply automatically.
Then() — execute and return the aggregate
CreateInstance(), loads GivenEvents(), and calls When(). Returns the resulting aggregate so you can inspect State, Changes, or any other aggregate property directly in a test method.
Calling Then() multiple times is safe — each call rebuilds the aggregate from scratch.
Emitted(params object[] events) — assert emitted events
events is a member of aggregate.Changes (the events raised during When). Uses subset semantics — the aggregate may emit additional events beyond those you assert. Calls Then() internally if it has not been called yet, so a minimal test method can consist of a single Emitted(...) call.
Returns the aggregate for method chaining or further inspection.
Instance — last produced aggregate
Then() call. Use this when you need to inspect state across multiple test methods without triggering When() again.
AggregateWithIdSpec<TAggregate, TState, TId>
AggregateSpec for aggregates whose State type carries a typed identity (State<TState, TId>). Automatically seeds the aggregate identity before When is called, so the state’s Id property is populated exactly as it would be when loading from a real event store.
Id — the aggregate identity
Id is null, the base CreateInstance() behaviour applies and no identity is pre-assigned.
AggregateWithIdSpec overrides CreateInstance() to call Registry.CreateTestAggregateInstance<TAggregate, TState, TId>(Id) when Id is non-null.
AggregateFactoryRegistry
The registry controls how aggregate instances are constructed. The global singleton is AggregateFactoryRegistry.Instance. Pass a custom registry to the spec constructor only when you have non-standard construction requirements (e.g. aggregate constructors that accept injected services). For the vast majority of aggregates the default behaviour — constructing via the parameterless factory — is correct and requires no configuration.
Complete example
The following example tests aBooking aggregate. The Given scenario starts from a room-booked event, the When records a payment, and several test methods each assert a different aspect of the outcome.
Using AggregateWithIdSpec
When your aggregate state type carries a typed Id property, use the AggregateWithIdSpec variant to have the identity automatically wired up:
Testing patterns
One spec class per scenario — keep eachAggregateSpec subclass focused on a single When action. Multiple test methods in the class then cover different assertions about that one outcome, and you can freely call both Emitted(...) and Then() within the same spec without repeating setup code.
Combine Emitted and Then in the same spec — Emitted performs event subset assertions and returns the aggregate, while Then gives you access to State, Changes, and any public aggregate properties for richer behavioral assertions.
Don’t assert order unless it matters — Emitted uses subset semantics. If event order is significant for your domain, inspect Then().Changes directly with your test framework’s ordering assertions.
No IEventStore required — AggregateSpec never touches a database or event store. The aggregate is hydrated and exercised entirely in memory, keeping tests fast and free of infrastructure setup.