如何正确配置模拟依赖项以使用 Autofac 测试 Web Api(ASP.NET 核心)控制器

How to properly configure mock dependencies for testing Web Api (ASP.NET Core) controllers using Autofac

我正在使用 ASP.NET Core (2.0) 和 Autofac,以及 Microsoft.AspNetCore.TestHost.TestServer 进行集成测试。但是,对于某些测试场景,我想注入一些服务模拟而不是 ConfigureContainer 方法中加载的实现(如此处所述:http://docs.autofac.org/en/latest/integration/aspnetcore.html#quick-start-with-configurecontainer)。

示例:

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());
    }
    ...
}

和测试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();
    }
   ...

我想做的是按原样使用 TestServer 和所有依赖项,但只是像测试示例中那样模拟的 IResellerProvider 。实现该目标的最佳方法是什么?当然,我可以为这种情况创建 TestStartup class,但我想知道处理这种情况的正确方法是什么。

我找到了一个工作正常的解决方法,它允许您在 .net 核心中注入任何其他依赖项 api。 您将在测试中启动此标准代码

var clientFactory = new WebApplicationFactory<Startup>();
var client = clientFactory.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(services =>
{

}));

var _httpClient = client.CreateClient();

现在您需要向 .ConfigureTestServices 传递一个 Action,您可以使用它来删除您在正常应用程序启动时的注册并添加另一个可以说它是假的 one.This 因为如果你在服务上使用调试器查看,你会看到所有你注册的都是预先发送的,你只需要替换你想要的moke.Here 是我使用的一个简单示例

RemoveVehicleServiceRegistrationFrom(services);
services.AddScoped<IVehicleService, FakeVehicleService>();

在 Remove 方法中,您只需像这样查找并删除旧的 registration.Something

private static void RemoveVehicleServiceRegistrationFrom(IServiceCollection services)
{
     var vehicleService = services.Single(x => x.ServiceType == typeof(IVehicleService));
     services.Remove(vehicleService);
}

最终版本是这样的

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);
}