Integration Testing in ASP.NET Core with example
Today in this article we will see how to perform Integration Testing in ASP.NET Core with examples.
Integration Testing is one of the XP practices of software development where features are developed iteratively with a small quantity (tested for their integration with other components) as they evolve.
Creating an Integration Testing project will require us to perform the below steps,
- Create Integration Test Project
- Add a Test Fixture
- Host a target service (Software Under Test) in Test Server( localhost)
- Perform HTTP operations on API
Getting Started
I shall be using the basic .NET Core example that we used in our last article on “Getting Started MongoDB in .NET Core with Examples“
Create Integration Test Project
Let’s add XUnit Test projects.
Please add xunit Nuget Packages to your test project.
A typical test project configuration looks as below,
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
We shall be looking at a very simple scenario of Service1 (Component1) communicating with the Database( Component2).
There are multiple ways to define Webhost for hosting the test application.
We shall be looking at the basic usage of WebApplicationFactory for both hosting and loading configurations of the target service( SUT) as required.
Creating Basic WebApplicationFactory
We shall be creating WebApplicationFactory to create a TestServer instance which will be our host.
We shall be using the same instance to load the required configuration.
For ASP.NET Core 3.1 or .NET 6
If you happen to create a service from scratch using the .NET Core 3.1 WebAPI template then for the Integration test project, you don’t need to override CreateHostBuilder.
This I found as per the design update in the .NET Core 3.1 version.
However, you can override the other methods like WithWebHostBuilder or ConfigureWebHost to load/unload some specific services/service providers as per the requirement.
So update class AppTestFixture is as below,
public class AppTestFixture : WebApplicationFactory<Startup>
{
//override methods here as needed for Test purpose
}
public class BooksAServiceIntegrationTests : IClassFixture<AppTestFixture>
{
readonly AppTestFixture _fixture;
readonly HttpClient _client;
public BooksAServiceIntegrationTests(AppTestFixture fixture)
{
_fixture = fixture;
_client = fixture.CreateClient();
}
[Theory]
[InlineData("/api/book")]
[InlineData("/api/book/1")]
public async void Get_GetBookListAll_Valid_Success(string url)
{
// Act
var response = await _client.GetAsync(url);
// Assert1
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// Assert2
Assert.Equal("application/json; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
With the above changes, once Test cases are executed, it will use the inbuilt Test Host which will be our Test Server.
In the above code fixture.CreateClient() will create a client for a self-hosted (using Test server) service instance.
This Test server will run as a local host and will host the service in its memory.
Having this test host available means we can run real tests within the developer machine and build servers using the CICD-build pipeline as needed.
Once the target service is hosted, we write the required test cases ensuring,
- Target service talks to other downstream services/components as per the expectations.
- Also, Target service returns proper responses to its upstream layers.
Best Practices for Service API Integration Testing,
- Make sure the Integration Test doesn’t take a long time
- Always scope your integration testing.
- They should be narrow and should verify integration with downstream and upstream both.
- Test the only permutation of the Test scenarios.
- Validate HTTP status code for success
- Validate API responses( Contract verification assuming it won’t break existing Consumers of API)
For more details please visit the below article as we deep dive into a few additional scenarios including API Contract Testing.
Please note that this however needed for a few versions of the .NET Core 3.0 preview.
Factory class WebApplicationFactory will support the host by default which uses a generic host builder of the target service created using CreateDefaultBuilder.
If you need HostBuilder for Custom Test configuration loading purposes then you can load the same using the above as discussed.
Here is the complete implementation for Theory with the fixture implementation,
public class BooksAServiceIntegrationTests : IClassFixture<AppTestFixture>
{
readonly AppTestFixture _fixture;
readonly HttpClient _client;
public BooksAServiceIntegrationTests(AppTestFixture fixture)
{
_fixture = fixture;
_client = fixture.CreateClient();
}
[Theory]
[InlineData("/api/book")]
[InlineData("/api/book/1")]
public async void Get_GetBookListAll_Valid_Success(string url)
{
// Act
var response = await _client.GetAsync(url);
// Assert1
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// Assert2
Assert.Equal("application/json; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
Let’s execute the API and check for a basic response and HTTP status code.
Finally, we are able to test Service endpoints( Component 1) and Database (Component 2) easily.
That’s All !! Please sound off your comments below.
Other references,
Summary
Today in this article we looked at how to create the Integration Testing project in the .NET core. We looked at how to use WebApplicationFactory for creating the test instance and performing integration testing and also discussed a few updates on host builder.
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.