Minimal .NET-facing provider micro-library for Observer.
If you are new to this surface, start with HOWTO.md before reading the individual snippets and starters.
This aims at the same DX bar as the C, Go, Rust, TypeScript, and Python libraries:
- authors write
Spec.Describe(...),Spec.Test(...),Spec.It(...), andSpec.Expect(...) - default identity is derived deterministically from explicit suite path plus test title
- optional
Spec.Id(...)provides a refactor-stable override when needed - observation is bounded and opt-in through
ctx.Observe().* - direct host and embedded
observedispatch are owned by the library
The common path stays human-first. The deterministic boundary stays explicit.
HOWTO.md: detailed user manual covering authoring, determinism, host transport, inventory derivation, and end-to-end workflowObserver.Dotnet.csproj: installable package metadata for the standalone .NET librarysrc/Observer.cs: public APItests/Observer.Dotnet.SelfTest/: self-test coverage for the .NET SDKexamples/ExampleSmoke/: tiny collection and execution exampleexamples/HostExample/: tiny directlistandrunhost exampleexamples/HostEmbedExample/: own-main styleobservenamespace example../../examples/dotnet-consumer/: standalone consumer-style example outside the SDK subtreestarter/: runnable project-shaped example with .NET build, provider host build, inventory derivation, suite run, and snapshot verificationstarter-embedded/: runnable app-shaped example where the application keepsMain()and routesobserve ...through its own CLIstarter-failure/: runnable failing companion showing the same provider flow with one intentionally failing exported test
If you want the full end-to-end workflow rather than isolated snippets, start with starter/, then read starter-embedded/, and then compare those with starter-failure/.
using Observer.Dotnet;
var tests = Spec.CollectTests(() =>
{
Spec.Describe("database", () =>
{
Spec.Test("access to the database", ctx =>
{
ctx.Stdout("ok\n");
Spec.Expect(true).ToBeTruthy();
});
});
});When Spec.Id(...) is omitted, Observer derives a deterministic identity from suite path, test title, and duplicate occurrence order.
Inside this repo, the examples use a project reference to Observer.Dotnet.csproj.
For a normal .NET project, the natural install paths are:
dotnet add reference path/to/Observer.Dotnet.csprojdotnet pack lib/dotnet/Observer.Dotnet.csprojand then consume the resulting package
The package multi-targets net8.0 and net10.0. The examples and starters target net8.0 so the default path stays mainstream.
If you want the closest thing in this repo to a normal external consumer, start with ../../examples/dotnet-consumer/.
dotnet run --project lib/dotnet/tests/Observer.Dotnet.SelfTest/Observer.Dotnet.SelfTest.csprojdotnet run --project lib/dotnet/examples/ExampleSmoke/ExampleSmoke.csprojdotnet run --project lib/dotnet/examples/HostExample/HostExample.csproj -- list
dotnet run --project lib/dotnet/examples/HostExample/HostExample.csproj -- observe --target pkg::smoke --timeout-ms 1000
dotnet run --project lib/dotnet/examples/HostExample/HostExample.csproj -- run --target pkg::fail --timeout-ms 1000The library owns the standard provider host transport for .NET too. A direct host can stay nearly trivial through Spec.HostMain(...).
If a project already owns its CLI, the library can also serve an embedded observe namespace. The runnable example lives in examples/HostEmbedExample/, and the full app-shaped workflow lives in starter-embedded/.