Stratara.Testing.EntityFrameworkCore
4.0.3
Prefix Reserved
dotnet add package Stratara.Testing.EntityFrameworkCore --version 4.0.3
NuGet\Install-Package Stratara.Testing.EntityFrameworkCore -Version 4.0.3
<PackageReference Include="Stratara.Testing.EntityFrameworkCore" Version="4.0.3" />
<PackageVersion Include="Stratara.Testing.EntityFrameworkCore" Version="4.0.3" />
<PackageReference Include="Stratara.Testing.EntityFrameworkCore" />
paket add Stratara.Testing.EntityFrameworkCore --version 4.0.3
#r "nuget: Stratara.Testing.EntityFrameworkCore, 4.0.3"
#:package Stratara.Testing.EntityFrameworkCore@4.0.3
#addin nuget:?package=Stratara.Testing.EntityFrameworkCore&version=4.0.3
#tool nuget:?package=Stratara.Testing.EntityFrameworkCore&version=4.0.3
Stratara.Testing.EntityFrameworkCore
Derived. The behaviour described here is specified under
openspec/specs/. Those specifications are the source; this page explains and illustrates them.
Spin up the real Stratara event-sourcing write stack — IEventSource, IAggregationService,
snapshots, and the EF Core write store — against a shared in-memory SQLite database, in one
call. You exercise production code paths (real serialization, real version tracking, real unique
constraints) without Postgres or Docker.
Builds on Stratara.Testing: the cross-cutting
dependencies are wired with its in-memory doubles (InMemoryKeyStore, TestSessionContextProvider).
Why not a hand-rolled in-memory IEventSource?
Because a bespoke fake would drift from production (subject resolution, concurrency detection,
outbox dispatch, snapshots). This package runs the genuine EventSource on SQLite instead, so your
tests verify the real behavior.
Example
await using var host = EventStoreTestHost.Create(s =>
s.AddAggregatesFromAssemblyContaining<Account>());
await host.ExecuteAsync(async events =>
{
await events.CreateAsync<Account>(id, new AccountOpened(id, tenantId, "Ada", 100m));
await events.AppendAsync<Account>(id, new AmountWithdrawn(30m));
await events.SaveChangesAsync();
});
var account = await host.AggregateAsync<Account>(id);
Assert.Equal(70m, account!.Balance);
Assert.Single(host.Outbox.Bundles); // the SaveChanges emitted one bundle
Contents
EventStoreTestHost— owns a shared open SQLite connection + a configured service provider; exposesExecuteAsync(IEventSource),AggregateAsync<T>(streamId), the presetSession, and the recordingOutbox.IAsyncDisposable.AddStrataraTestingEventStore<TWriteDbContext>(connection, tenantId)— the lower-level DI extension if you compose the provider yourself.StrataraTestWriteDbContext— a ready-made concrete write context (no subclass boilerplate).RecordingEventBundleOutboxDispatcher— captures emitted bundles for assertions.
Notes
- The SQLite connection is
:memory:and shared across every DbContext the unit of work mints — it must stay open for the host's lifetime (the host manages this; dispose it when done). - Register your aggregates (
AddAggregatesFromAssemblyContaining<T>()) so event payload types deserialize on rehydration.
Dependencies
Stratara.Testing,Stratara.Infrastructure,Stratara.EventSourcing.EntityFrameworkCore,Stratara.Shared,Stratara.Abstractions,Stratara.ContractsMicrosoft.EntityFrameworkCore.Sqlite
Reference it from test projects only.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.EntityFrameworkCore.Sqlite (>= 10.0.11)
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Stratara.Abstractions (>= 4.0.3)
- Stratara.Contracts (>= 4.0.3)
- Stratara.EventSourcing.EntityFrameworkCore (>= 4.0.3)
- Stratara.Infrastructure (>= 4.0.3)
- Stratara.Shared (>= 4.0.3)
- Stratara.Testing (>= 4.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.3 | 33 | 9/3/2026 |
| 4.0.2 | 41 | 9/3/2026 |
| 4.0.1 | 36 | 9/2/2026 |
| 4.0.0 | 80 | 8/31/2026 |
| 4.0.0-preview.1 | 45 | 8/31/2026 |
| 3.4.0 | 80 | 8/28/2026 |
| 3.3.0 | 96 | 8/25/2026 |
| 3.2.3 | 96 | 8/22/2026 |
| 3.2.2 | 97 | 8/14/2026 |
| 3.2.1 | 108 | 8/2/2026 |
| 3.2.0 | 111 | 7/18/2026 |
| 3.1.7 | 119 | 7/1/2026 |
| 3.1.6 | 113 | 6/22/2026 |
| 3.1.5 | 117 | 6/22/2026 |
| 3.1.4 | 118 | 6/15/2026 |
| 3.1.3 | 119 | 6/10/2026 |
| 3.1.2 | 130 | 6/5/2026 |
Three fixes to the same complaint: a host composed exactly as the documentation describes did not
start. Each one was a registration the composites assumed somebody else had made — a tracer, a unit
of work, a Redis connection — and each is now made by the registration that needs it. Nothing that
already worked changes: every fix defers to a registration the host makes itself, in either order,
so the lines a working host added to get past these gaps can simply be deleted. Additive on every
published surface.
### Fixed
- **A host without Redis starts and dispatches.** Every composite that carries a dispatcher
registered the projection-replay state, and its only implementation took a Redis connection that
no composite registers, so a host composed as documented failed at its first dispatch unless it
also ran Redis and called `AddCaching()`. `AddProjectionReplayState()` now chooses at first
resolution: with a registered `IConnectionMultiplexer` the Redis-backed state as before, without
one an in-process state with the same lease semantics — and a warning, once at start-up
(`104_012`), that replay coordination is confined to that process, so a replay requested there
suppresses publication there only. A deployment whose replay must reach several hosts registers
the shared connection, in either order. Redis-backed hosts observe no change.
- **Registering a store context now registers its unit of work.**
`AddNpgsqlWriteDbContextFactory<T>()` registered the context factory, the context and the default
connection resolver but not the `IWriteUnitOfWork` that the event source, the outbox dispatcher and
the command worker take from the container — and nothing else in the published packages did, so a
host composed exactly as documented failed at its first command with a dependency-injection error.
The write registration now try-adds a scoped `IWriteUnitOfWork` over its context, and
`AddNpgsqlReadDbContextFactory<T>()` try-adds `IProjectionsUnitOfWork` and `IReadUnitOfWork`
likewise. A unit of work the host registers itself, before or after, is still the one used; a
hand-written registration can simply be deleted.
- **`AddMediator()` no longer requires the host to register an OpenTelemetry `Tracer`.** The
mediator traces every dispatch and obtained its tracer from the host, but nothing registered one,
so a host that called `AddMediator()` and nothing else failed at the first resolve of `IMediator`.
`AddMediator()` now registers a fallback that emits the dispatch spans from the framework's
`Stratara.Application` activity source — a host that subscribes to framework telemetry sees them,
a host that subscribes to nothing pays for nothing. A `Tracer` the host registers, before or after
`AddMediator()`, is still the one used, so no existing host changes behaviour; the registration
line can simply be deleted. The samples, the README and the package README no longer carry it.