本文介绍了在AspNetCore与TestServer的集成测试中模拟和解决Autofac依赖关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用AspNetCore 2.2跟随(更多)这里的文档: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2

I'm using AspNetCore 2.2Following (moreless) the docs here:https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2

我正在使用Autofac,我的Startup类具有以下方法:

I am using Autofac, my Startup class has the following methods:

public void ConfigureServices(IServiceCollection services)
public void ConfigureContainer(ContainerBuilder containerBuilder) //this is where things can be registered directly with autofac and runs after ConfigureServices
public void Configure(...) //the method called by runtime

按照其文档的建议,我使用Autofac的方式是使用Program.cs like this

The way I use Autofac, as recommended by its docs, is by having Program.cs like this

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseKestrel()
            .ConfigureServices(services => services.AddAutofac())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .ConfigureAppConfiguration((builderContext, config) =>
            {
                var env = builderContext.HostingEnvironment;
                config
                    .AddJsonFile("appsettings.json", false, true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true)
                    .AddEnvironmentVariables();
            });
}

我现在将TestServer用于我的测试项目,我想在其中使用真正的Startup类.但是我想修改其中一个依赖项.

I am now using TestServer for my test project where I want to use the real Startup class. But I would like to modify one of the dependencies.

我已经看到WebHostBuilder.ConfigureTestServices(services => {});

所以我尝试了以下操作:

so I tried the following:

public abstract class ComponentTestFeature
    : Feature
{
    protected HttpClient HttpClient { get; }

    protected ComponentTestFeature()
    {
        var configuration =
            new ConfigurationBuilder()
                .AddJsonFile("appsettings.Test.json")
                .Build();

        var webHostBuilder =
            new WebHostBuilder()
                .ConfigureServices(services => services.AddAutofac())
                .ConfigureTestServices(services =>
                {
                    services.AddScoped<IEventStoreManager, MockEventStoreManager>();
                })
                .UseConfiguration(configuration)
                .UseStartup<Startup>();

        var server = new TestServer(webHostBuilder);
        HttpClient = server.CreateClient();
        var myService = server.Host.Services.GetRequiredService<IEventStoreManager>();
    }
}

如您所见,我想对IEventStoreManager使用MockEventStoreManager实现,因此这是应该由容器解决的实现.但是,这不能按预期方式工作,myService解析的是原始实现,真正的实现,而不是模拟的实现.

As you can see I want to use a MockEventStoreManager implementation for IEventStoreManager so that this is the implementation that should be resolved by the container. However this is not working as expected and myService resolved is the original implementation, the real one, not the mock one.

有人知道我怎么能实现我想要的吗?

Does anybody know how could I achieve what I want?

更新1:经过更多调查后,我不得不在github AspNetCore上创建一个问题,因为扩展方法是在ConfigureContainer之前执行的,因此我无法真正覆盖autofac依赖项,也无法稍后再获取autofac容器. https://github.com/aspnet/AspNetCore/issues/6522

UPDATE 1:After more investigation I had to create an issue on github AspNetCore because the extension method is executed before the ConfigureContainer, therefore I cannot really override autofac dependencies nor retrieve autofac container later on.https://github.com/aspnet/AspNetCore/issues/6522

更新2:仅供参考,这就是Startup.cs的样子.如您所见,除了mvc外,所有依赖项都已在autofac的容器中注册.

UPDATE 2:Just FYI, this is how the Startup.cs looks like. As you can see all the dependencies but mvc are registered in autofac's container.

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

// This is where things can be registered directly with autofac and runs after ConfigureServices, so it will override it
public void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterType<EventStoreManager>().As<IEventStoreManager>();
}

我想做的是在测试中对IEventStoreManager使用MockEventStoreManager实现,所以我需要(从测试项目中)重写Autofac的注册方法.

and what I want to do is to use MockEventStoreManager implementation for IEventStoreManager in my tests, so I need to override (from my test project) that Autofac's registration in a nice way.

推荐答案

使用 ConfigureTestContainer

//...
.ConfigureServices(services => services.AddAutofac())
.ConfigureTestContainer<ContainerBuilder>(builder => {
    builder.RegisterType<MockEventStoreManager>().As<IEventStoreManager>();
})
//...

这应该避免获得由Startup.ConfigureContainer添加为

This should avoid getting the actual implementation that is added by Startup.ConfigureContainer as

参考默认注册

ConfigureTestContainerStartup.ConfigureContainer之后被调用,因此最后一次向模拟注册是该服务的默认提供程序.

ConfigureTestContainer is invoked after the Startup.ConfigureContainer so the last registration with the mock would be the default provider of the service.

这篇关于在AspNetCore与TestServer的集成测试中模拟和解决Autofac依赖关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 21:12