繁体   English   中英

如何在 ASP.NET Core 集成测试中覆盖来自其他容器的 DI 注册

[英]How to override DI registration from other container in ASP.NET Core integration test

我在 asp.net core startup.cs 文件中有以下注册:

    public void ConfigureContainer(ContainerBuilder builder)
    {
       builder.RegisterType<UserService>().As<IUserService>();
    }

这是配置 Autofac 容器。 我还有另一个集成测试项目,其中有一个 CustomWebApplicationFactory 类,我正在尝试替换 IUserService 接口的实现。

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestServices(services =>
        {
            services.AddSingleton<IUserService, TestUsersService>();
        });
    }

调试测试项目好像不行,IUserService的实现还是UserService。

我尝试使用 ASP.NET Core 内置 IServiceCollection 直接在 Startup.ConfigureServices 方法中注册 UserService 并且它在调试时工作:

services.AddSingleton<IUserService, UserService>();

那么,当我使用 Autofac 作为 IoC 容器并且集成测试项目将按预期正常工作时,我该如何解决问题?

您可能会遇到操作顺序问题。 一般来说,最后获胜。 这适用于 Autofac 和基本的 Microsoft DI 容器。

假设您已阅读有关 Autofac ASP.NET Core 集成的文档,您将看到当ConfigureContainer就位时,操作顺序大致如下:

  • 特定于 WebHost 的 ConfigureServices
  • 启动类 ConfigureServices
  • 启动类 ConfigureContainer

在适当的位置添加 ConfigureTestServices 时,它看起来(虽然我没有逐步完成)它在 WebHost 和启动类 ConfigureServices 之后运行......但它仍然在 ConfigureContainer 之前运行。

这很容易测试 - 创建一个具有三种不同实现的服务接口。 在每个级别注册不同的实现。 解析控制器中的接口。 你得到了哪一个? 那是最后一个运行。 现在从应用程序中删除该注册并重试。 你得到的下一个是什么? 这是倒数第二个。 等等。

Autofac 采用预先构建的IServicesCollection并循环遍历它,将其添加到本机 Autofac 容器中。 一旦发生这种情况,您是否修改集合都没有关系。 Autofac 无法控制 ASP.NET Core 中启动机制的执行顺序; 它只知道 ASP.NET Core 说:“这是要继续导入的最终服务集合!” 如果这不是在正确的阶段发生,您将不得不做以下两件事之一:

  • 使用 Microsoft 注册语言而不是本机 Autofac,将您需要覆盖的注册从ConfigureContainer移到ConfigureServices方法之一。
  • 以其他方式执行覆盖,例如使用TestASPNETCORE_ENVIRONMENT设置并提供ConfigureTestContainer方法。 (环境特定注册方法的示例在文档中。)

像这样使用 ContainerBuilder 时:

    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<UserService>().As<IUserService>();
    }

您必须使用 ConfigureTestContainer 而不是 ConfigureTestServices,如下所示:

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestContainer<ContainerBuilder>(containerBuilder =>
            {
                containerBuilder.RegisterType<TestUsersService>().As<IUserService>();
            });
    }

这是在调用 ConfigureContainer 之后执行的,并将使用TestUsersService正确覆盖IUserService

对于来自 google 的那些,我想添加到 Michael 的出色回答中,即ConfigureTestContainer不适用于Microsoft从 .NET Core 3.0 开始通过 Web 主机推荐的通用主机。 然而,Autofac 团队的 Alistair Evans 提出了一种解决方法 不幸的是,它依赖于可能会在 .NET 5.0 中删除的已弃用的IStartupConfigureContainerFilter

这意味着当前在 .NET 5.0 中,当使用通用主机时,无法在集成测试中模拟外部 DI 容器注入的依赖项。

幸运的是,来自 ASP.NET 团队的 David Fowler 正在调查这个问题

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM