c# - 在 AspNetCore 与 TestServer 的集成测试中模拟和解决 Autofac 依赖关系
问题描述
我正在使用 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 的注册。
解决方案
使用ConfigureTestContainer向容器构建器注册模拟实现以进行测试
//...
.ConfigureServices(services => services.AddAutofac())
.ConfigureTestContainer<ContainerBuilder>(builder => {
builder.RegisterType<MockEventStoreManager>().As<IEventStoreManager>();
})
//...
Startup.ConfigureContainer
这应该避免获得由as添加的实际实现
如果多个组件公开相同的服务,Autofac 将使用最后注册的组件作为该服务的默认提供者:
参考默认注册
ConfigureTestContainer
在 之后调用,Startup.ConfigureContainer
因此最后一次注册模拟将是服务的默认提供者。
推荐阅读
- boost - 检查 Boost::boost 目标是否存在失败
- python - Pygame 将 28x28 像素缩放为 420x420
- reactjs - 如何在材质 UI 中为每个选项卡创建具有多个标签的自定义选项卡?
- java - 使用java识别和禁用(只读)word文档(.docx)的特定部分
- javafx - 如何在不选择其项目的情况下使用 tableView 的所有数据更新数据库?
- c# - 使用 dll 获取 NUnit 项目名称
- c# - 如何在 Unity3D 中沿轨迹移动立方体
- php - 在 WooCommerce 的我的帐户“帐户详细信息”中添加一个复选框
- python - Django Form 无效,无法弄清楚原因
- ansible - Ansible 比较远程服务器上的两个文件