Bobcat is a spec-driven integration testing framework for .NET and the successor to Storyteller. It is built for the hardest integration testing jobs: systems with databases, message brokers, background processing, and many moving parts.
- Author specifications as ordinary xUnit.net, TUnit, NUnit or MSTest tests, and let Bobcat render them as readable specifications. A Roslyn source generator turns your step helpers and marker comments into recorded steps at compile time, with no runtime reflection.
- Supervise a large suite so its results can be trusted. It can split the suite across worker processes, isolate resources per lane, retry within budgets, and report flakiness honestly instead of burying it. A suite can also stay resident, running the specifications a run console asks for.
- Specify end to end. Executable specifications still read as requirements, and they can be
scaffolded slice by slice from an Event Model. Bobcat has first-class support for the Critter
Stack (Wolverine, Marten, Polecat and Fisher)
through
WolverineFx.Bobcat(Testing with Bobcat), while Bobcat itself takes no JasperFx or Wolverine dependency.
Your specifications are your test framework's own tests, so they show up in dotnet test, your
IDE's Test Explorer, and CI like any other test.
Access the docs here. For any of your questions, including about the rest of the Critter Stack, join our Discord channel. It is the best way to reach us quickly. You can also raise questions or report problems through GitHub Issues.
While Bobcat is open source, JasperFx Software offers paid support and consulting contracts for Bobcat.
Become a Sponsor on GitHub by sponsoring monthly or one time.
| Package | What it is for |
|---|---|
Bobcat |
The runtime: the projected specification engine, verification, rendering, the monitor wire and the resilience vocabulary. No JasperFx or Wolverine dependency; the Critter Stack vocabulary (CritterStackScenario) ships in WolverineFx.Bobcat from the Wolverine repository |
Bobcat.Generators |
The source generator: step interceptors, marker-comment steps, the Event Model fold and compile-time table checks |
Bobcat.Supervisor |
Drives any MTP test host as worker processes, with retry, isolation, and parallel lanes |
WolverineFx.Bobcat |
Published from the Wolverine repository: Given/When/Then for Wolverine handlers and event-sourced slices, documented at Testing with Bobcat. Replaces the retired Bobcat.Wolverine |
Bobcat.Xunit / Bobcat.TUnit / Bobcat.NUnit / Bobcat.MSTest |
Renders an existing xUnit.net v3, TUnit, NUnit or MSTest suite as specifications, without changing how it runs |
Bobcat.EventModel |
Imports the Event Modeling platform's own format and writes it as C# stub types plus an EventModelDefinition |
Bobcat.Console |
The bobcat global tool: reads, validates, and converts Event Model files, and keeps a suite Bobcat does not own available to a run console |
dotnet add package BobcatSee Getting Started for wiring up a first spec project.
Before getting started you will need the following in your environment:
Available here. The repository builds with the .NET 10 SDK. Most
packages target both net9.0 and net10.0; Bobcat.Generators targets netstandard2.0 because it
is a Roslyn analyzer.
A few integration tests need a real PostgreSQL database. The fastest way to get one
is the docker-compose.yml at the repository root:
docker compose up -dor, through the build (see below), ./build.sh Docker. Postgres is published on 5445, so it
will not collide with one you may already run.
To use your own database instead, set BOBCAT_POSTGRES to its connection string. Without a
database, the tests that need one skip locally and say so. On CI they never skip, so a missing
database fails the build instead of passing silently.
A current LTS release (the docs workflow uses Node 24), to run the VitePress documentation site locally. See Documentation.
bobcat.slnx at the repository root is the solution for everything under src/. It is the only
solution file at the root, so dotnet build and dotnet test pick it up without being told.
src/contains the packages, their test projects, and the sample hosts the tests drive (Bobcat.Xunit.Samples,Bobcat.Supervisor.ProjectedWorker).- The sample applications moved to the Wolverine repository with the Critter Stack vocabulary in 1.0.0-rc.2 (#744).
spikes/contains throwaway research code, kept for reproducibility, with its own solution.build/is the Nuke build project described below.docs/is the documentation site.
Package versions are managed centrally with NuGet's
Central Package Management:
src/Directory.Packages.props holds every version, and a PackageReference never carries its own
Version. Its header comment says which projects may reference JasperFx (only the tools).
- Tests use xUnit.net v3, Shouldly, and NSubstitute, and run on Microsoft.Testing.Platform rather than VSTest. Every test project is a self-executing test host.
- Nuke is used for build automation.
- VitePress builds the documentation site.
The Nuke build is the single definition of what CI does. Every GitHub Actions workflow calls it, so
a green ./build.sh CI on your machine means the same thing as a green push.
| Description | Windows Commandline | PowerShell | Linux / macOS Shell | DotNet CLI |
|---|---|---|---|---|
| Restore, build and test (the default) | build.cmd |
build.ps1 |
./build.sh |
dotnet run --project build/Build.csproj |
| Start the Docker services | build.cmd docker |
build.ps1 docker |
./build.sh docker |
dotnet run --project build/Build.csproj -- docker |
Everything the tests workflow runs |
build.cmd ci |
build.ps1 ci |
./build.sh ci |
dotnet run --project build/Build.csproj -- ci |
| The TUnit-hosted tests CI leaves out for now (#521) | build.cmd tunittests |
build.ps1 tunittests |
./build.sh tunittests |
dotnet run --project build/Build.csproj -- tunittests |
Pack every package to artifacts/packages |
build.cmd pack |
build.ps1 pack |
./build.sh pack |
dotnet run --project build/Build.csproj -- pack |
| List every target and parameter | build.cmd --help |
build.ps1 --help |
./build.sh --help |
dotnet run --project build/Build.csproj -- --help |
Targets combine, so ./build.sh docker ci starts the services and then runs the full CI build.
The build uses the Debug configuration locally and Release on a CI server. Override it with
--configuration Release.
You can also work with the solution directly using the dotnet CLI:
dotnet build
dotnet test
# Tests run on Microsoft.Testing.Platform; global.json puts `dotnet test` in its MTP mode, so the
# project is `--project` and test-host options go straight on the command line (no `--`)
dotnet test --project src/Bobcat.Tests/ --filter-class "*PipelineTests"Note:
./build.sh dockerstarts the compose services. The Marten-backed tests and the samples that needed Postgres moved to the Wolverine repository (#744).
CI is GitHub Actions only, and each workflow is a thin wrapper around the Nuke build:
| Workflow | Runs | When |
|---|---|---|
tests.yml |
./build.sh CI, with a Postgres service: the suite, then the results schema checked against the last release's |
every push |
ui-smoke.yml |
./build.sh UiSmoke: packs the bobcat tool with its UI, starts bobcat ui and checks it, Chromium included |
pushes touching src/ or build/ |
ui-frontend.yml |
./build.sh UiContracts, then typecheck, Vitest and the Vite build of the bobcat ui page |
pushes touching src/Bobcat.Ui.FrontEnd/, src/Bobcat.Ui/Contracts/ or build/ |
publish.yml |
./build.sh CI Pack, then pushes to nuget.org |
v* tags, or manually |
docs.yml |
builds and deploys the documentation site | manually |
To change what CI does, change build/Build.cs, build/UiSmoke.cs or build/Contracts.cs, not the
workflows.
Two files are generated and never committed, so that parallel branches touching the wire do not
conflict on them: the frontend's TypeScript contracts (src/Bobcat.Ui.FrontEnd/src/messages/monitor-events.ts
and relayRoutes.ts) and the results file's JSON Schema. After one dotnet build, the frontend's
npm ci, npm run dev, npm test and npm run build generate the TypeScript themselves; so does
./build.sh UiContracts. ./build.sh Pack generates both.
All the documentation is written in Markdown in the docs/ directory and published as a
static site at bobcat.jasperfx.net using
VitePress. The Markdown in docs/ is the site. Navigation and sidebars
are defined in docs/.vitepress/config.mjs.
To run the docs locally, with auto-refresh on any changes:
npm install
npm run docsTo check a production build before publishing:
npm run docs:build # builds to docs/.vitepress/dist
npm run docs:preview # serves that build locallyThe site is deployed by running the docs.yml workflow manually from the Actions tab. Nothing
deploys the documentation automatically on push.
Project graphics and the "Ember on Ink" color tokens live in docs/public/
and docs/.vitepress/theme/style.css.
Copyright © Jeremy D. Miller and contributors.
Bobcat is provided as-is under the MIT license. For more information see LICENSE.
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
