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

问题描述 投票:3回答:2

我在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容器并且集成测试项目能够按照我的预期正常工作时,如何解决问题呢?

c# integration-testing autofac asp.net-core-webapi
2个回答
4
投票

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

假设you've read through the docs on Autofac ASP.NET Core integration你会看到当ConfigureContainer到位时,操作顺序大致是:

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

在添加ConfigureTestServices时,看起来(虽然我没有介入)它在WebHost和Startup类ConfigureServices之后运行......但它仍然在ConfigureContainer之前运行。

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

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

  • 使用Microsoft注册语言而不是本机Autofac,将需要覆盖的注册移出ConfigureContainer并进入ConfigureServices方法之一。
  • 以其他方式执行覆盖,例如使用ASPNETCORE_ENVIRONMENTTest设置并提供ConfigureTestContainer方法。 (环境特定的注册方法的例子在the docs。)

2
投票

当像这样使用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之后执行的,并将使用IUserService正确覆盖TestUsersService

© www.soinside.com 2019 - 2024. All rights reserved.