Lately I've been experimenting with the new WebApplicationFactory in .NET 6.0 together with custom Umbraco API controllers to verify that each API endpoint is up and running and that they return the expected output.
I've already done this in the form of Unit Tests in the official Umbraco Unit Testing documentation, but this time instead of using Unit Tests to test the core functionallity, I'll be doing Integration (or E2E depending on what you want to call it) testing to verify the running behaviour of my application and its API endpoints.
In this article I'll be using the new WebApplicationFactory to spin up a running in-memory application using my Umbraco projects Program.cs file, which will give me an actual HttpClient that I can use in my test class. Nice huh?!
Not only that, but in the last example I'll be showing you how to override specific services that you might want to mock or override in your integration tests and give some examples to when this might be useful.
Let's get started!
To start of, I have a empty installation of Umbraco 9 (in this example v9.2.0) and an empty NUnit Test Project in the same solution. My test project is referencing my Umbraco project and I've made no tweaking what so ever on any of the Program.cs or Startup.cs classes.
Create an API controller
In this example I've simply copy & pasted the example API controller from the official Umbraco documentation and so far I've made no tweaking to it at all. Later we will add some custom services and modify the endpoint but for now you can just head over and copy the controller: source code.
Create a WebApplicationFactory
Since my test project is referencing my Umbraco project, I can now create a test factory that uses my Umbraco projects Program.cs file, which in turn uses the Startup.cs file of my Umbraco project. For now we are not going to tweak this factory at all, we will just use it as is. (We'll tweak it a little later in this article): source code.
Create some tests
Now I can use this factory to create an HttpClient that I may use in my tests. Here I've created two example tests: The first test just verifies that the response content type is "application/json; charset=utf-8" and the second test parses the response json and compare it to my expected string array.
These tests themselves are not important and can probably be written better, but they are here to demonstrate how you may now use the HttpClient and perform actions on our running application and verify the output.
What's going on here?
It's important that we understand what we are actually doing here. We have no mock frameworks or fake configurations at all in our test project. We are spinning up an actual running instance of our application in memory and performing test verifications on it. We are using the actual database, filesystem and implementation code as if we would have opened up our web browser (or Postman) and request specific endpoints.
Obviously since we are using a running instance, these tests will take a lot longer to execute that a unit test with fake/mocks, but since Umbraco 9 spins up really fast compared to the old .NET framework version, the tests in this article completes in less than a few seconds on my computer.
Override or mock specific services
But what if we actually do want to override a specific service in our integration tests? In general it doesn't make a lot of sense to mock services in Integration/E2E tests because then what are you really testing? The whole point of spinning up a running application is so that we may test actual behaviour of our application so why would we want to start replacing service behaviour in our integration tests?
The reasons my be plenty, but here's one: Let's assume that our previous API controller endpoint not only returns some data but also it sends an email to an admin using a service like SendGrid or Mailgun. This might look something like this (the content of the EmailService is not important here, just imagine that its a service that sends an email using some SMTP settings defined in your project): source code.
Using our previous tests, this will actually result in us sending an actual email to our clients admin every time we run our integration tests. This might be a little annoying for the client. Now imagine we have our tests running continuously on our build server any time you check in your branch, this will result in A LOT of emails being sent which might hurt your deliverability reputation and your emails might start ending up in the junk folder.
Sure, you probably have specific SMTP configurations for your local development and build server so that emails does not get sent to the admin, but remember this is just an example of how you may override specific services for whatever reason.
In my example I actually dont want to send an email at all and therefor I will override the behaviour of the EmailService in a FakeEmailService: source code.
And then configure it in my factory WebHostBuilder: source code.
Now all my tests will run all fine without any tweaking in each specific test, they will run and complete just as they did before but no email will be sent when the endpoints gets called from within my tests.
In this article we've seen how we may perform Integration tests on our Umbraco API controllers (or any controller for that matter) using an actual HttpClient thanks to the WebApplicationFactory. We've also seen an example of how you can override specific services in the tests (for whatever reason).
More examples of how to use the WebApplicationFactory and how you can customize it to your needs may e found on the official Microsoft Documentation page.
I'll definitely use the WebApplicationFactory integration tests more in my upcoming Umbraco 9 projects alongside my regular unit tests. Hope this article was helpful.
Cheers friends! ❤️