Less plumbing
Setup moves out of the test.
The same scenario against the same application, written as a plain fixture and with ProtoTest. The scenario lines stay; the plumbing around them is composed once for the suite or declared on the test that needs it.
Compare both files, line by line →- Run the application
A factory per fixtureThe suite host- A tenant of its own
SetUp and a helperAn attribute- Authenticate each call
Shared default headersPer test, from its context- Clean up after a failure
TearDown, if SetUp got farOwned, reversed and traced
Evidence
A failure explains itself.
Every call, check, wait and cleanup lands in a .prototrace archive next to the report. Open it and the failing check is one step away, with the values that differed and the source line that asserted them.
The trace also shows time nothing was recorded, so a real wait is visible instead of guessed.
Test execution / REST · GET /api/v1/organization
Failedexecution
assert.json.shape from ProtoTest.RestException message
JsonShapeMismatchExceptionShape mismatch failed with 1 error(s):• [$.status]: Values did not match. (Expected: "past_due", Actual: "active")
32 33await Task.Delay(TimeSpan.FromSeconds(1));34 35using var organization = await Proto.Context.Rest().GetAsync("/api/v1/organization");36organization37 .Should.HaveHttpStatus(HttpStatusCode.OK)38 .Should.MatchShape(new { status = SubscriptionStatuses.PastDue });39}40
One model
Different boundaries. The same test.
Choose the integrations your scenario crosses. Each joins the same host, context, cleanup and trace, so one test can write through an API and read back from the database or the browser.
Exercise your APIs
REST, GraphQL and gRPC clients with shared authentication, shape checks and contract coverage.
SupportedArrange data and inspect the store
Reusable test data, test-scoped SQL connections and EF Core contexts, with optional transaction rollback.
SupportedFollow a journey in the browser
Page objects and flows through Playwright or Selenium, with screenshots and page coverage.
SupportedPublish and await messages
In-memory messaging or RabbitMQ. Add the MassTransit bridge when you need its test harness.
Supported · MassTransit previewCompose the environment
ASP.NET Core, background workers and run-owned containers. Aspire and WireMock are available in preview.
Supported · preview extensionsReach devices and documents
Typed device clients over WebSocket or MQTT, and assertions on generated Excel workbooks.
PreviewEvery integration → · Recipes that combine them · Build one for your own domain
How it fits
Your runner runs the tests. ProtoTest holds what is around them.
- 01
Compose the host
Applications, clients and infrastructure, registered once for the suite.
Host composition → - 02
Arrange the context
Attributes and builders prepare the identity, data and clients one test needs.
Execution context → - 03
Own the cleanup
Whatever a test provisions is released in reverse order, also when it fails.
Lifecycle and cleanup → - 04
Keep the evidence
Calls, checks and cleanup land in the test’s trace, report and coverage.
Trace and reports →
Keep your runner and your assertions. Add a setup class and the integrations you need, then move one scenario at a time. Compare the setup · Choose your runner · Adoption and exit costs
35–36 msper-test median in a 1,000-test benchmark, with its limits →Try it
Your first suite, ready to run.
The template creates a small API and four integration tests. The .NET 10 SDK is enough; the default starter runs without containers or a browser.
After the green run, the trace and HTML report are under Shop.Tests/bin/Debug/net10.0/TestResults/.
dotnet new install ProtoTest.Templates
dotnet new prototest -n Shop
cd Shop
dotnet testWhy ProtoTest exists
Once an integration suite grows, most of the work shifts to setup, infrastructure and failures that only happen sometimes. ProtoTest gives every integration the same context, lifecycle and trace, so that work is solved once. What is specific to your application stays in your test project. Project and support