简体   繁体   English

在 AspNetCore 与 TestServer 的集成测试中模拟和解决 Autofac 依赖项

[英]Mocking and resolving Autofac dependency in integration test in AspNetCore with TestServer

I'm using AspNetCore 2.2 Following (moreless) the docs here: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2我正在使用 AspNetCore 2.2 以下(更多)文档: https ://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2

I am using Autofac, my Startup class has the following methods:我正在使用 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

The way I use Autofac, as recommended by its docs, is by having Program.cs like this我使用 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();
            });
}

I am now using TestServer for my test project where I want to use the real Startup class.我现在将 TestServer 用于我的测试项目,我想在其中使用真正的 Startup 类。 But I would like to modify one of the dependencies.但我想修改其中一个依赖项。

I have seen that there is a method available on WebHostBuilder to .ConfigureTestServices(services => {});我已经看到WebHostBuilder上有一种方法可以用于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>();
    }
}

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.正如你可以看到我想要使用一个MockEventStoreManager实施IEventStoreManager所以,这是应该由容器来解决实现。 However this is not working as expected and myService resolved is the original implementation, the real one, not the mock one.然而,这并没有按预期工作,并且 myService 解决的是原始实现,真正的实现,而不是模拟实现。

Does anybody know how could I achieve what I want?有谁知道我怎样才能实现我想要的?

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

UPDATE 2: Just FYI, this is how the Startup.cs looks like.更新 2:仅供参考,这就是 Startup.cs 的样子。 As you can see all the dependencies but mvc are registered in autofac's container.如您所见,除了 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>();
}

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.我想要做的是在我的测试中为IEventStoreManager使用MockEventStoreManager实现,所以我需要以一种很好的方式覆盖(从我的测试项目)Autofac 的注册。

Register the mocked implementation with the container builder for the test using ConfigureTestContainer使用ConfigureTestContainer向容器构建器注册模拟实现以进行测试

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

This should avoid getting the actual implementation that is added by Startup.ConfigureContainer as这应该避免获得由Startup.ConfigureContainer添加的实际实现作为

If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service :如果多个组件公开相同的服务, Autofac 将使用最后注册的组件作为该服务的默认提供者

Reference Default Registrations参考默认注册

ConfigureTestContainer is invoked after the Startup.ConfigureContainer so the last registration with the mock would be the default provider of the service. ConfigureTestContainerStartup.ConfigureContainer之后被调用,所以最后一次注册到 mock 将是服务的默认提供者。

Adding to Nkosi's excellent answer , I'd like to mention that ConfigureTestContainer does not work with the generic host recommended over the web host by Microsoft as of .NET Core 3.0.除了 Nkosi 的出色回答之外,我想提到ConfigureTestContainer不适用于Microsoft从 .NET Core 3.0 开始通过 Web 主机推荐的通用主机。 There is however a workaround proposed by Alistair Evans from the Autofac team .然而,Autofac 团队的 Alistair Evans 提出了一种解决方法 Unfortunately, it relies on the deprecated IStartupConfigureContainerFilter that has been removed in .NET 5.0.不幸的是,它依赖于已在 .NET 5.0 中删除的已弃用的IStartupConfigureContainerFilter

This means that currently in .NET 5.0 there is no way to mock dependencies injected by an external DI container in integration tests when using the generic host.这意味着当前在 .NET 5.0 中,当使用通用主机时,无法在集成测试中模拟外部 DI 容器注入的依赖项。

Luckily, David Fowler from the ASP.NET team is looking into the issue .幸运的是,来自 ASP.NET 团队的 David Fowler 正在调查这个问题

There are a couple of options:有几个选项:

  • Have a custom implementation of your dependency in your testserver project在您的 testserver 项目中自定义实现您的依赖项

  • Implement and manually register a mocked implementation of your dependency with a nugget like "Moq"使用“Moq”之类的金块实现并手动注册您的依赖项的模拟实现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 C# 中使用 Hotchocolate GraphQL 和 TestServer 进行集成测试 - Integration test with Hotchocolate GraphQL and TestServer in C# 使用autofac解析控制器时出现依赖性错误 - Dependency error while resolving controller with autofac 识别解析实例的依存关系-IoC(autofac) - Identify the dependency resolving an instance - IoC (autofac) 使用Autofac和Moq进行集成测试 - Integration Test Using Autofac and Moq Net Core-集成测试-TestServer-真实http连接 - Net Core - Integration test - TestServer - real http connection 在StartUp中使用Autofac解决每用户/每请求的依赖性 - Resolving per-user/per-request dependency with Autofac in StartUp Hangfire Autofac集成无法解析具有注册依赖项的服务 - Hangfire Autofac integration is not able to resolve service with registred dependency TransactionScope 不会在 per-test TearDown 中回滚以使用 NUnit 和 TestServer 进行集成测试 - TransactionScope doesn't rollback in per-test TearDown for integration testing using NUnit and TestServer 为使用 IdentityServer 4 进行身份验证的 AspNetCore API 构建集成测试 - Building an integration test for an AspNetCore API that uses IdentityServer 4 for Auth 使用测试主机或 WebApplicationFactory 的 ASPNetCore Web API 集成测试 - ASPNetCore Web API integration tests using Test Host or WebApplicationFactory
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM