簡體   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