Setting up integration tests using the ASP.NET Core WebHostBuilder


It’s a real pleasure to write tests for ASP.NET Core, be it unit or integration.

When it comes to writing integration tests, the two main concerns are wiring up an application which behaves as close to the real deal as possible, and replacing any required or desired parts with mocks.

In the following I’ve summarized how we simplify writing integration tests for our service and data layers by using the standard WebHostBuilder to do the grunt work of wiring up the dependencies for our SUT.


Our HttpContext-agnostic integration tests are all set up following the same pattern:

  1. Wire up a WebHostBuilder which in turn builds a IWebHost.
    1.1 Default services are automatically added using the ConfigureServices method of the application’s startup class.
    1.2 Mocks/stubs/spies are injected as needed.
  2. Use the IServiceProvider exposed via the IWebHost.Services property to get the SUT.
  3. Run tests against the SUT.

The following code uses NUnit for assertions and NSubstitute for mocking.


The WebHostBuilderFactory facilitates wiring up a WebHostBuilder with any modifications required by our tests, e.g. replacing dependencies with mocks, stubs or spies:

using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

internal static class WebHostBuilderFactory
    public static IWebHostBuilder Create<TStartup>(
        params Action<IServiceCollection>[] testSpecificServiceConfigurations) 
        where TStartup : class
        var contentRootPath = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\src\App");
        return new WebHostBuilder().UseContentRoot(contentRootPath)
            .ConfigureServices(services =>
                // Modify services as required.
                foreach (var serviceConfiguration in testSpecificServiceConfigurations)


The ServiceCollectionExtensions facilitate mock injection. Having a toolbox of extension methods to replace often used services helps keep the test suite readable and to the point:

using System;
using Microsoft.AspNet.Authentication;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;

internal static class ServiceCollectionExtensions
    public static void Replace<TRegisteredType>(this IServiceCollection services, TRegisteredType replacement)
        for (var i = 0; i < services.Count; i++)
            if (services[i].ServiceType == typeof (TRegisteredType))
                services[i] = new ServiceDescriptor(typeof (TRegisteredType), replacement);

    public static void SetSystemClock(this IServiceCollection services, DateTime date)
        var clock = Substitute.For<ISystemClock>();
        clock.UtcNow.Returns(new DateTimeOffset(date, TimeZoneInfo.Local.GetUtcOffset(date)));


The following is a simple test which uses the code shown above to create a ServiceProvider wired up with all the default services of the application and mocked versions of IMyDependency and ISystemClock:

public void MyServiceDoesAwesomeStuffTwoYearsAgo()
    // Arrange
    var myDependency = Substitute.For<IMyDependency>();
    var webHostBuilder = WebHostBuilderFactory.Create<MyStartup>(
             services => services.Replace<IMyDependency>(myDependency), 
             services => services.SetSystemClock(DateTime.Now.AddYears(-2)));
    var serviceProvider = webHostBuilder.Build().Services;
    var myService = serviceProvider.GetRequiredService<IMyService>();
    var expected = "awesome stuff";

    // Act
    var actual = myService.DoStuff();

    // Assert
    Assert.That(actual, Is.EqualTo(expected));

One thought on “Setting up integration tests using the ASP.NET Core WebHostBuilder

  1. This was a great guide, but I image that core updates since then have made the ‘ConfigureServices’ method called before the Startup’s ConfigureServices method.

    Instead, use ‘ConfigureTestServices’ (same syntax), which runs after Startup ConfigureServices and allows you to replace services as you would expect

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s