I'm using ASP.NET Core (2.0) with Autofac
, and a Microsoft.AspNetCore.TestHost.TestServer
for integration testing. However, for some test scenarios, I would like to inject some service mocks instead of the implementations loaded in ConfigureContainer
method (as described here: http://docs.autofac.org/en/latest/integration/aspnetcore.html#quick-start-with-configurecontainer).
Example:
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(s => s.AddAutofac())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
public class Startup
{
...
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new Modules.ApiModule());
}
...
}
And the test class:
public class BasicControllerTests
{
TestServer server;
HttpClient client;
public BasicControllerTests()
{
var resellerRepo = new Mock<IResellerProvider>();
resellerRepo.Setup(a => a.Query())
.Returns(new[] {
new Model.Reseller
{
Id = Guid.NewGuid(),
Code = "R1",
Name = "Reseller 1"
}
}.AsQueryable());
// How to inject mock properly in the lines below?
server = new TestServer(new WebHostBuilder()
.ConfigureServices(a => a.AddAutofac())
.UseStartup<Startup>());
client = server.CreateClient();
}
...
What I would like to do is to use the TestServer
with all the dependencies as they are, but just the IResellerProvider
mocked as in the test example. What is the best way to accomplish that? Of course, I could create a TestStartup
class for this exact case, but I would like to know what is the proper way to handle this situation.
I found a workaround that works just fine and lets you inject any other dependency in .net core api. You will have this standard code to start up in your tests
var clientFactory = new WebApplicationFactory<Startup>();
var client = clientFactory.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(services =>
{
}));
var _httpClient = client.CreateClient();
Now you need to pass to .ConfigureTestServices an Action and you can use this to remove the registration you have on the normal app startup and add another one that lets say it's a fake one.This in possible because if you look with debugger on services you will see that all those you registered are presend and you will just need to replace the ones you want to moke.Here is a simple example that I used
RemoveVehicleServiceRegistrationFrom(services);
services.AddScoped<IVehicleService, FakeVehicleService>();
In the Remove method you just need to find and remove old registration.Something like this
private static void RemoveVehicleServiceRegistrationFrom(IServiceCollection services)
{
var vehicleService = services.Single(x => x.ServiceType == typeof(IVehicleService));
services.Remove(vehicleService);
}
Final version looks like this
private HttpClient _httpClient;
[OneTimeSetUp]
public void Setup()
{
var clientFactory = new WebApplicationFactory<Startup>();
var client = clientFactory.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(services =>
{
RemoveVehicleServiceRegistrationFrom(services);
services.AddScoped<IVehicleService, FakeVehicleService>();
}));
var _httpClient = client.CreateClient();
}
private static void RemoveVehicleServiceRegistrationFrom(IServiceCollection services)
{
var vehicleService = services.Single(x => x.ServiceType == typeof(IVehicleService));
services.Remove(vehicleService);
}