How do I replace service implementations for Web API integration testing using TestHost.TestServer in .NET 5

733 Views Asked by At

I am trying to move my integration tests from WebApplicationFactory to TestServer in .NET 5. In my existing implementation I can override ConfigureWebHost and call IWebHostBuilder.ConfigureServices to replace service implementations with mocks. This runs after the Startup code, allowing me to remove the production implementation and add the mock.

When trying to achieve the same thing using TestServer, ConfigureServices always runs before the Startup code, no matter in which order I do the configuration, meaning I always end up with both implementations in the services collection and it seems "last one wins", i.e. the prod version of the service always runs.

How can I configure the builder to use my test version?

I am using XUnit, so perhaps am not using it in the right way re IClassFixture etc.

Here is my code:

public sealed class IntegrationTests : IDisposable
{
    private TestServer Server { get; }
    private HttpClient Client { get; }

    public IntegrationTests()
    {
        var builder = new WebHostBuilder()
            .UseConfiguration(new ConfigurationBuilder().AddJsonFile("appsettings.development.json").Build())
            .UseSerilog()
            // Changing the order of the following two lines doesn't help
            .UseStartup<Startup>()
            .ConfigureServices(UseDummyUserRepository);

        Server = new TestServer(builder);
        Client = Server.CreateClient();
    }

    private void UseDummyUserRepository(IServiceCollection services)
    {
        //Following line doesn't work as the service is not yet configured
        //services.Remove(services.First(s => s.ServiceType == typeof(IUserRepository)));
        services.AddTransient<IUserRepository, DummyUserRepository>();
    }
2

There are 2 best solutions below

1
On

This post contains some more info which might be useful.

From my testing the order of execution in an integration test is as follows.

Startup.ConfigureServices
IWebHostBuilder.ConfigureServices
IWebHostBuilder.ConfigureTestServices
Startup.ConfigureContainer

So the issue comes when you attempt to override a service in IWebHostBuilder.ConfigureServices if that service is actually defined in Startup.ConfigureContainer

I tried using IWebHostBuilder.ConfigureTestContainer but it did not appear to be executed.

How to override DI registration from other container in ASP.NET Core integration test

0
On

I've found out about the existence of TryAddTransient, which does the job but feels like a bit of a hack.