FastEndpoints is an alternative web framework built on ASP.NET Core primitives to reinforce the Request-Endpoint-Response (REPR) Design pattern. In summary, FastEndpoints lets you focus on building endpoint-focused APIs instead of dealing with the ceremony of something like MVC or the potential analysis-paralysis of Minimal API decisions.
I think the framework does a lot correctly and can help teams accelerate creating APIs without dealing with the plumbing and code shuffling that typically accompanies large applications. That said, confidence is an essential part of any complex system, and that confidence naturally comes in the form of tests.
This post will explore testing FastEndpoints using a few community NuGet packages and some helper classes.
Your First FastEndpoint Endpoint
When starting a FastEndpoints project, it’s best to start with an empty ASP.NET Core template. You’ll also need to add the FastEndpoints
NuGet package to your web project. Your version number might differ from the one in this post.
You can set up your Program.cs
file after you’ve installed the Fast Endpoints package. Fast Endpoints is secure by default, so we allow access to all endpoints for this demo. Of course, we’ll only have one for this demo, but feel free to add as many as you’d like.
Next, in an Api
folder, let’s add a Root
class. This class will be our root endpoint, accessible at /
.
Running your web application, you should now be able to hit the root endpoint and retrieve the following result (your time may differ).
Hello, World @ 05:03:00 PM
Let’s write some unit tests!
Testing FastEndpoints Using XUnit
Our goal is to be able to test each endpoint in isolation. The philosophy of the REPR pattern is that all endpoints should be testable in isolation, so it should be straightforward.
Let’s start by adding a few NuGet packages to a new XUnit test project. The most important being Microsoft.AspNetCore.Mvc.Testing
. Don’t worry; while the name mentions Mvc
, it is a general-purpose testing library for ASP.NET Core. You’ll also need to reference your previous web project.
Add the following file to your test project, and feel free to replace the namespace and move the classes to any file structure you’d like. These classes will help us write concise tests later.
Now, let’s write a test and explain what’s happening.
Each unit test will spin up an instance of our web application, allowing us to call any endpoint using an HTTP client. Our App
class takes in any dependencies (Singleton, Scoped, or Transient) and replaces any instance of that registration in our ServiceCollection
. In the case of this test, we’re replacing our instance of ISystemClock
with a TestSystemClock
, which allows us to control time.
We want to keep these instances as part of our unit test class, which enables us to massage state to pass a test. Given the nature of FastEndpoints, I feel this also makes more sense, as each endpoint could have its own set of dependencies you’ll need to swap out.
You should now have a passing test!
Manipulating Auth for FastEndpoints
Adding the ability to bypass authentication is a bit more complex, but not by much. Your web application will need an implementation for UserOverrideMiddleware
. Add the following code to that project.
The middleware will look for a UserOverride
in the services container. If it is present, then we’ll override the currently authenticated user. It’s important to register this middleware before the authentication and authorization middleware.
You’ll also need to modify your Program.cs
file to look like the following. Note we only register the UserOverrideMiddleware
for development. You don’t want this middleware in production.
Let’s modify our test to allow for supplying a user. Then, back in your unit test project, adjust your test class to include a new User
property and a new test using it.
Running your test now, you should get a passing test along with the following output result.
Nice! Now you have a test harness for all your new FastEndpoint endpoints. So you can keep your tests readable and straight to the point.
Conclusion
Building on ASP.NET Core primitives allows us to exercise FastEndpoints like we would Minimal API endpoints or MVC controllers. You could certainly adapt this approach to any ASP.NET Core web framework, and I think it helps keep your tests from devolving into setup soup. You may also want to consider moving the creation of your App
instance into a class fixture if you find instantiating the dependencies add considerable time to your unit testing runs.
If you’d like to see a complete sample of this post, please go to my GitHub repository. As always, thanks for reading, and be sure to let me know if you found this post helpful. Cheers!