ProtoTest is a foundation for integration testing on .NET 8, 9 and 10.
Hard to describe it. You could call it a foundation, a large test framework or something else. I have a preference for "foundation", since that best describes what I personally want ProtoTest to be.
It's something you can build upon to do integration testing without having to build all of the supporting infrastructure yourself.
Core gives you the foundation of ProtoTest.
It provides a lifecycle independent of the test runner you choose, so ProtoTest itself doesn't lock you into one runner. Adapters are available for NUnit, xUnit, TUnit and MSTest.
Each test gets its own ProtoExecutionContext. That context can share state between hooks, attributes and the test itself, while also giving you access to configured clients and integrations, observations, tracing and other shared functionality.
The idea is that integrations don't each live in their own little world. They participate in the same test execution and can make use of the same lifecycle, context and tracing.
ProtoTest currently integrates with REST, GraphQL, gRPC, SQL, Entity Framework Core, Playwright, Selenium, RabbitMQ, ASP.NET Core, Testcontainers, OpenTelemetry and more.
This definitely is a large list. I picked these because they're commonly used, but if something is missing, you can easily create an integration yourself, extend an existing one or open a discussion and I'll check it out.
Use only what your test suite needs. You're not obligated to use everything.
I admit, ProtoTest hides a lot of setup for you, or puts it behind abstract layers.
That makes tests cleaner, but it can also make figuring out what went wrong harder.
To help with that, I took inspiration from Playwright traces.
The built-in integrations hook into the tracing provided by Core. At the end of a run, ProtoTest writes a .prototrace file containing the execution trace, including setup and teardown, observations, state, attachments and additional reports when configured.
That brings us to ProtoTrace. The place where you can hopefully find what went wrong with your test.
ProtoTrace · Open an interactive trace
I love programming, but especially building tools and solving abstract problems.
Integration testing can get rough, especially for bigger applications such as SaaS applications. There's so much infrastructure, setup and so on.
My focus is and always has been clean and readable code. ProtoTest is my response to how messy that setup gets.
It's built from scratch, but on what I learned from a testing framework I wrote by hand years ago. I had already been thinking about building ProtoTest since March, but was in a bit of a coding slump and never really got started. Once I did, it moved very quickly.
Read more about why I built ProtoTest.
[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.ShouldHaveNoErrors();
}This is a simple example combining the REST and GraphQL integrations. The focus lies on a clean test with most of the infrastructure moved out of the test once it has been configured.
The test can focus on the behavior. If something goes wrong, its lifecycle, operations and checks are written to the same .prototrace file.
In essence, you could call it that. They wrap around proven frameworks that do certain jobs really well.
If they already do their job well, why wrap them?
I'm a huge fan of AAA since discovering that principle. Tests should simply be that readable: Arrange-Act-Assert. Straight to the point.
That's why the wrappers exist. They integrate with the Core and they're my opinionated view on how I want to test with them.
Common application setup can stay outside the test. Setup that matters to the scenario should still be visible.
Is it the best for everyone? Probably not. But it might just help someone do integration testing.
dotnet new install ProtoTest.Templates
dotnet new prototest -n Shop
cd Shop
dotnet testA little bonus since ProtoTest might seem like a weird name. I tend to use Proto for projects that match my vision. As a student, I created ProtoEngine (a C++ 2D game engine, also available on GitHub).
Why Proto? Is it short for Prototype?
Yes, you'd be correct. Prototype in the sense of looking simple and straight to the point.
That's always my goal, even if I don't succeed in every step or implementation. It has to look readable and simple while still being extendable.
That's where the name ProtoTest comes from: Proto, from Prototype, combined with Testing. Bringing some of that simplicity and directness to integration testing.
Yes, extensively. This is the first personal project where I have used AI this much.
I had already built a similar testing framework by hand before the AI boom. ProtoTest was built from scratch, but the vision for most of it already existed.
AI helped me work through ideas, alternatives and implementations much faster. I know what it can produce without enough direction, so I used different models, compared their suggestions, said no often and kept control over what ProtoTest became.
Do I regret using it? I don't know yet.
ProtoTest is still what I wanted to build.
Read the longer explanation in the documentation.
ProtoTest is available under the MIT license. Issues and contributions are welcome.
