Skip to main content

Integration testing foundation for .NET

Test the whole journey. Trace every layer.

Compose your application, data and clients once for the suite. Every test gets its own context, owned cleanup and a trace that explains what happened, across APIs, databases, browsers and messages.

.NET 8, 9 & 10 · NUnit, xUnit, MSTest & TUnit · MIT

[ProtoTest]
[SignedInAs]
public async Task RestWritesAreVisibleThroughGraphQL()
{
using var created = await Proto.Context.Rest()
.Body(new CreateProjectRequest("atlas"))
.PostAsync("/api/v1/projects");
created.Should.HaveHttpStatus(HttpStatusCode.Created);
using var projects = await Proto.Context.GraphQL()
.Query("projects", new { first = 10 })
.ExpectAsync(new
{
totalCount = 1,
nodes = new[] { new { name = "atlas", status = ProjectStatuses.Active } }
});
projects.Should.HaveNoErrors();
}
PlatformJourney.cs. The class selects the application and provisions a Northstar member.

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 →
Without ProtoTest35
With ProtoTest13
lines of plumbing in each fixture, for the same scenario
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.

ProtoTrace viewer · failing check

Test execution / REST · GET /api/v1/organization

CheckAssert response shape

Failed2.2 ms · +1.15 s into the testexecution

assert.json.shape from ProtoTest.Rest

Exception messageJsonShapeMismatchExceptionShape mismatch failed with 1 error(s):• [$.status]: Values did not match. (Expected: "past_due", Actual: "active")
FailureDrills.cs:36Northstar.ProtoTest.FailureDrills.ARealWaitDoesNotCloseTheDueWindow
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 
Validated document
"status": "past_due" "active"
Test 12 from prototest-demo.prototrace, as the inspector shows it.

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.

Every 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.​

  1. 01

    Compose the host

    Applications, clients and infrastructure, registered once for the suite.

    Host composition →
  2. 02

    Arrange the context

    Attributes and builders prepare the identity, data and clients one test needs.

    Execution context →
  3. 03

    Own the cleanup

    Whatever a test provisions is released in reverse order, also when it fails.

    Lifecycle and cleanup →
  4. 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/.

Installation and options · Learn with the Northstar sample

Create and run Shop
Runner
dotnet new install ProtoTest.Templates
dotnet new prototest -n Shop
cd Shop
dotnet test

Why 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

Latest release: 1.1.0 · 30 sep 2026Release notes →