With the release of ASP.NET Core 3.1 earlier this week it is time to get onboard with the future. As this is the current LTS (Long Term Support) version this is the version to get up to speed with.

With the new framework developments over the past few years testing has been a first class citizen in the ecosystem. Unit tests have never been easier to write with libraries such as xUnit and Moq. But that’s unit tests, how do we write integration tests? Let’s find out.

What is an Integration Test?

So what is an Integration test? If you ask different people you will get different answers but they should all be along the same lines. Integration tests are the ability to run multiple units of functionality together to make sure they function as a whole when connected together. Each unit of functionality should have their own unit tests but it adds another layer of testing to check they work as expected together.

Let’s take a look at how ASP.NET Core 3.1 can help us write an integration test.

Basic Setup

An integration test starts off life very similarly to a unit test.

[Fact]
public async Task Test2()
{
    // code goes here
}

First we create a new the Generic Host Builder. In this we want to configure the Web Host style of hosts.

var hostBuilder = new HostBuilder()
    .ConfigureWebHost(webHost =>
    {
        // Add TestServer
        webHost.UseTestServer();

        // Specify the environment
        webHost.UseEnvironment("Test");

        webHost.Configure(app => app.Run(async ctx => await ctx.Response.WriteAsync("Hello World!")));
    });

This specifies that you want to use the TestServer instead of a full deployable server implementation of IServer.

Note: to use UseTestServer() you will require referencing the Microsoft.AspNetCore.Mvc.Testing nuget package. Thanks to Markus for highlighting this clarification.

We then specify the type of Environment we are working in. This is the same as if we specify Development or Staging or Production in the main application.

We then configure the app. This is very similar to how you specify and configure the main application middleware pipeline in the Startup classes Configure method.

Once we’ve got a host builder setup we can build and start it.

var host = await hostBuilder.StartAsync();

So far so good!

Now we have a working and running in-memory server we want to get access to a HttpClient instance to initiate the call to this server.

var client = host.GetTestClient();

Now we’ve got a client we can write the remainder of the test as if we were writing a client to access a simple REST based api.

var response = await client.GetAsync("/");

Using the response we can assert an expected result.

The Integration Test in Full

Let’s take a look at the full integration test.

[Fact]
public async Task BasicIntegrationTest()
{
    // Arrange
    var hostBuilder = new HostBuilder()
        .ConfigureWebHost(webHost =>
        {
            // Add TestServer
            webHost.UseTestServer();

            // Specify the environment
            webHost.UseEnvironment("Test");

            webHost.Configure(app => app.Run(async ctx => await ctx.Response.WriteAsync("Hello World!")));
        });
    
    // Create and start up the host
    var host = await hostBuilder.StartAsync();

    // Create an HttpClient which is setup for the test host
    var client = host.GetTestClient();

    // Act
    var response = await client.GetAsync("/");

    // Assert
    var responseString = await response.Content.ReadAsStringAsync();
    responseString.Should().Be("Hello World!");
}

As you can see it is still setup in the AAA (Arrange, Act, Assert) unit testing style. This aids with structure for the test.

This example is based the one from Andrew Lock’s blog post. If you are looking at upgrading ASP.NET Core 2.x to 3.x then I’d highly recommend reading his series on it.

Conclusion

In this post we have looked at a basic example of setting up a test server and running an integration test. Obviously there are a lot more things we can do with this and I will look to post more advanced scenarios soon.

Any questions/comments then please contact me on Twitter @WestDiscGolf

Part 1 - This post

Part 2 - Integration Testing with ASP.NET Core 3.1 - Testing Your Application

Part 3 - Integration Testing with ASP.NET Core 3.1 - Swapping a dependency

Part 4 - Integration Testing with ASP.NET Core 3.1 - Remove the Boiler Plate

Part 5 - [Integration Testing with ASP.NET Core 3.1 - Swapping a Dependency with Moq][ParkFiveLink]

Part 6 - Integration Testing with ASP.NET Core 3.1 - Set Default Headers for All Clients