Functional testing your ASP.NET WEB API
WebAPI
19 Articles
In this article, let's learn about how to do Functional Test in WebAPI in ASP.NET Core.
Table of Contents
Introduction
Functional Testing ensure that an app's components function correctly at a level that includes the app's supporting infrastructure, such as the database, file system, and network. The main difference between functional testing and unit testing is that application's infrastructure components like database, file system, etc are mocked with unit tests. But with functional testing, we want to ensure that the whole app is working as expected with all of these components combined together. ASP.NET Core supports functional tests using a unit test framework with a test web host and an in-memory test server.
Why Functional Testing ?
Functional tests evaluate an app's components on a broader level than unit tests. Unit tests are used to test isolated software components, such as individual class methods. Functional tests confirm that two or more app components work together to produce an expected result, possibly including every component required to fully process a request.
The characteristics of functional tests include:
- Use the actual components that the app uses in production.
- Require more code and data processing.
- Take longer to run.
Therefore, limit the use of functional tests to the most important infrastructure scenarios. If a behavior can be tested using either a unit test or an functional test, choose the unit test.
Prerequisite
You need to have an ASP.NET Core WebAPI project. If you don't have one, you can create one from Visual Studio.
We are going to learn this with .NET 8 Web API project.
The default project template contains a WeatherForecastController. We are going to use this controller for our functional testing. Here is the API response when we run the project.
Steps to do Functional Testing
Let's see the steps to do functional testing in ASP.NET Core Web API.
Create a XUnit Test Project.
- Add Package Reference to Nuget Package Microsoft.AspNetCore.Mvc.Testing.
- Optionally make sure you have all Nuget Packages updated to latest version in all your projects.
Add Project Reference to your API project in your test project.
Now we need to expose the implicitly defined Program class to the test project by adding public partial class Program { } to the end of Program.cs in Web API.
- WebApplicationFactory<TEntryPoint> is used to create a TestServer for the functional tests. TEntryPoint is the entry point class of the SUT, usually Program.cs.
We can add CustomWebApiFactory.cs in our test project to create a custom WebApplicationFactory<TEntryPoint>. We can then override ConfigureWebHost method to set the environment to Test. This is shown in the below code.
Code Sample - Custom Web API Factory
That's it we are all set. Now its time to write our first functional test. Let's write a test to check if the API returns the expected response.
We can add a new class WeatherForecastControllerTests.cs in our test project and add the following code.
Code Sample - First Functional Test
In the above code, we are inheriting from XUnit IClassFixture<CustomWebApiFactory> and then create HttpClient from factory within our test and make a HTTP GET call to weatherforecast endpoint and deserialize the response to List<WeatherForecast>. We are then asserting the count of our response. We can also assert the values of the response in the same way.
Note, I'm using XUnit IClassFixture<CustomWebApiFactory> to create a single instance of the factory for all tests in the class. To learn more about XUnit's IClassFixture, you can refer to the official documentation
The tests will run in the following flow.
- Start Test Method.
- Create WebApplicationFactory.
- Run Program.cs.
- Service Registration.
- Build Web Application.
- Create HTTP Client.
- Test Code Execution.
Now lets run the test and see the result.
The tests are passing. We can also write tests to check if the API returns the expected response for different HTTP methods like POST, PUT, DELETE, etc. in the same way.
Before we wrap up, we can do some additional changes to test code to make it more reusable. The first step is to make a abstract BaseTest class and inherit our tests from that.
Code Sample - Abstract Base Test
Now let's adjust our WeatherForecastControllerTests to inherit from BaseTest and use the HttpClient from BaseTest class as shown below.
Code Sample - Functional Test Inherited from Base Test
Good. Now we can do final improvement which is to assert the Http Status Code of the response and move deserialization and error logging using ITestOutputHelper into a separate HttpClientExtensions class. This small investment will help us to write more tests easily in the future.
Code Sample - Functional Test HttpClientExtensions
Now we can use the HttpClientExtensions in our tests as shown below.
Code Sample - Functional Test with BaseTest and HttpClientExtensions
Now lets run the test and see the result.
Summary
In this article, we learnt about what is funtional test and how to write functional test in ASP.NET Web API. Functional test help us to test end to end functionality of our application without mocking any infrastructure dependencies. This is very useful to test the application in real world scenario. In our next article we will learn about how to do functional testing in ASP.NET Web API with database.