Why Deepstaging¶
Your Tests Write Themselves (Almost)¶
The .NET testing story has been an industry-wide shrug for years. Pick a mocking framework. Learn its DSL. Configure a test DI container that mirrors production. Spend more time setting up tests than writing them.
Deepstaging generates your test infrastructure alongside your production code. No mocking framework. No reflection. No proxy generation.
One line. CreateConfigured() gives you a fully wired runtime with stubs for every capability. The same test runs against stubs or real Postgres — one environment variable switches between them:
dotnet test # unit — in-memory stubs
INTEGRATION=true dotnet test # integration — real infrastructure
Write Domain Code, Not Plumbing¶
Every .NET project starts the same way: wire DI, write repository interfaces, implement them, add validation, configure MediatR, set up messaging, write test fakes. Weeks of infrastructure before a single line of domain logic.
Deepstaging asks you to declare your intent with attributes. The compiler generates everything else:
[EffectsModule(typeof(IEmailService))]
public sealed partial class EmailEffects;
[Runtime]
public sealed partial class AppRuntime;
That produces DI registration, effect wrappers, capability interfaces, test stubs, and OpenTelemetry tracing. You didn't configure anything. You stated what exists.
From Prototype to Production Without a Rewrite¶
Every module works in-memory by default. No database, no message broker, no connection strings during development. When you're ready for production, swap the backing infrastructure — your domain code and tests don't change:
builder.AddAppRuntime(rt =>
{
rt.AddAppStorePostgres(connectionString);
rt.PublishToServiceBus<OrderingEvents>();
});
Same entities. Same handlers. Same tests. Infrastructure is a deployment concern.
No Black Boxes¶
Everything Deepstaging produces is visible in your generated/ folder. No opaque runtime, no hidden middleware.
Want to understand what [EffectsModule] does? Open the generated file. Need to debug? Step into it — it's just C#. If you stop using Deepstaging, the generated code still compiles against Deepstaging.Runtime (a small package with no generators).
Fails Loud and Early¶
.NET's IConfiguration gives you null for a misspelled key. A missing service registration blows up on the first request. A dev-only fake sneaks into production.
Deepstaging catches all of these at startup:
[ConfigRoot]generatesValidateOnStart()— missing sections fail before the first request[DevelopmentOnly]services are detected in production and the app refuses to start[Secret]properties are routed todotnet user-secrets— the analyzer catches accidental exposure- 60+ compile-time analyzers catch structural bugs in your IDE as you type
Built-In Observability, Not Bolted On¶
Every generated effect method is instrumented with OpenTelemetry tracing. No manual span creation. No decorator pattern. One config toggle:
Under Aspire, traces appear in the dashboard automatically. Each module gets its own ActivitySource, metrics track success/failure rates, and correlation context flows through every span.