我正在使用AspNetCore 2.2 遵循(更多)此处的文档: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
我正在使用Autofac,我的Startup类具有以下方法:
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
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类。但是我想修改其中一个依赖项。
我已经看到WebHostBuilder
到.ConfigureTestServices(services => {});
上有一种方法
所以我尝试了以下操作:
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>();
}
}
如您所见,我想对MockEventStoreManager
使用IEventStoreManager
实现,因此这是应该由容器解决的实现。但是,这不能按预期工作,myService解析的是原始实现,真正的实现,而不是模拟的实现。
有人知道我怎么能实现我想要的吗?
更新1: 经过更多调查后,我不得不在github AspNetCore上创建一个问题,因为扩展方法是在ConfigureContainer之前执行的,因此我无法真正覆盖autofac依赖项,也无法稍后再获取autofac容器。 https://github.com/aspnet/AspNetCore/issues/6522
更新2: 仅供参考,这就是Startup.cs的样子。如您所见,除了mvc外,所有依赖项都已在autofac的容器中注册。
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>();
}
我想做的是在测试中为MockEventStoreManager
使用IEventStoreManager
实现,所以我需要(从测试项目中)重写Autofac的注册方法。
答案 0 :(得分:5)
使用ConfigureTestContainer向容器构建器注册模拟实现以进行测试
//...
.ConfigureServices(services => services.AddAutofac())
.ConfigureTestContainer<ContainerBuilder>(builder => {
builder.RegisterType<MockEventStoreManager>().As<IEventStoreManager>();
})
//...
这应该避免获取由Startup.ConfigureContainer
添加为的实际实现
如果有多个组件公开相同的服务, Autofac将使用最后注册的组件作为该服务的默认提供程序:
ConfigureTestContainer
在Startup.ConfigureContainer
之后被调用,因此最后一次向模拟注册是该服务的默认提供程序。
答案 1 :(得分:1)
除了Nkosi出色的answer之外,我想提到ConfigureTestContainer
不能与.NET Core 3.0的通用主机recommended over the web host by Microsoft一起使用。但是有一个workaround proposed by Alistair Evans from the Autofac team。不幸的是,它依赖于已弃用的IStartupConfigureContainerFilter
,它可能会在.NET 5.0中删除。
这意味着当前在.NET 5.0中,当使用通用主机时,无法在集成测试中模拟外部DI容器注入的依赖项。
幸运的是,来自ASP.NET团队is looking into the issue的David Fowler。
答案 2 :(得分:0)
有两种选择:
在测试服务器中具有依赖项的自定义实现 项目
使用“ Moq”之类的块实现并手动注册依赖项的模拟实现