Reconfigure dependencies when Integration testing ASP.NET Core Web API and EF Core

@ilya-chumakov's answer is awesome. I just would like to add one more option

3. Use ConfigureTestServices method from WebHostBuilderExtensions.

The method ConfigureTestServices is available in the Microsoft.AspNetCore.TestHost version 2.1(on 20.05.2018 it is RC1-final). And it lets us override existing registrations with mocks.

The code:

_server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
    .ConfigureTestServices(services =>
    {
        services.AddTransient<IFooService, MockService>();
    })
);

Here are two options:

1. Use WebHostBuilder.ConfigureServices

Use WebHostBuilder.ConfigureServices together with WebHostBuilder.UseStartup<T> to override and mock a web application`s DI registrations:

_server = new TestServer(new WebHostBuilder()
    .ConfigureServices(services =>
    {
        services.AddScoped<IFooService, MockService>();
    })
    .UseStartup<Startup>()
);

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        //use TryAdd to support mocking IFooService
        services.TryAddTransient<IFooService, FooService>();
    }
}

The key point here is to use TryAdd methods inside the original Startup class. Custom WebHostBuilder.ConfigureServices is called before the original Startup, so the mocks are registered before the original services. TryAdd doesn't do anything if the same interface has already been registered, thus the real services will not be even touched.

More info: Running Integration Tests For ASP.NET Core Apps.

2. Inheritance / new Startup class

Create TestStartup class to re-configure ASP.NET Core DI. You can inherit it from Startup and override only needed methods:

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env) : base(env) { }

    public override void ConfigureServices(IServiceCollection services)
    {
        //mock DbContext and any other dependencies here
    }
}

Alternatively TestStartup can be created from scratch to keep testing cleaner.

And specify it in UseStartup to run the test server:

_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());

This is a complete large example: Integration testing your asp .net core app with an in memory database.