XUnit 依賴註入

来源:https://www.cnblogs.com/weihanli/archive/2018/10/08/dependency-injection-in-xunit.html
-Advertisement-
Play Games

現在的開發中越來越看重依賴註入的思想,微軟的 Asp.Net Core 框架更是天然集成了依賴註入,那麼在單元測試中如何使用依賴註入呢? 本文主要介紹如何通過 XUnit 來實現依賴註入, XUnit 主要藉助 SharedContext 來共用一部分資源包括這些資源的創建以及釋放。 ...


XUnit 依賴註入

Intro

現在的開發中越來越看重依賴註入的思想,微軟的 Asp.Net Core 框架更是天然集成了依賴註入,那麼在單元測試中如何使用依賴註入呢?

本文主要介紹如何通過 XUnit 來實現依賴註入, XUnit 主要藉助 SharedContext 來共用一部分資源包括這些資源的創建以及釋放。

Scoped

針對 Scoped 的對象可以藉助 XUnit 中的 IClassFixture 來實現

  1. 定義自己的 Fixture,需要初始化的資源在構造方法里初始化,如果需要在測試結束的時候釋放資源需要實現 IDisposable 介面
  2. 需要依賴註入的測試類實現介面 IClassFixture<Fixture>
  3. 在構造方法中註入實現的 Fixture 對象,併在構造方法中使用 Fixture 對象中暴露的公共成員

Singleton

針對 Singleton 的對象可以藉助 XUnit 中的 ICollectionFixture 來實現

  1. 定義自己的 Fixture,需要初始化的資源在構造方法里初始化,如果需要在測試結束的時候釋放資源需要實現 IDisposable 介面
  2. 創建 CollectionDefinition,實現介面 ICollectionFixture<Fixture>,並添加一個 [CollectionDefinition("CollectionName")] Attribute,CollectionName 需要在整個測試中唯一,不能出現重覆的 CollectionName
  3. 在需要註入的測試類中添加 [Collection("CollectionName")] Attribute,然後在構造方法中註入對應的 Fixture

Tips

  • 如果有多個類需要依賴註入,可以通過一個基類來做,這樣就只需要一個基類上添加 [Collection("CollectionName")] Attribute,其他類只需要集成這個基類就可以了

Samples

Scoped Sample

這裡直接以 XUnit 的示例為例:

public class DatabaseFixture : IDisposable
{
    public DatabaseFixture()
    {
        Db = new SqlConnection("MyConnectionString");

        // ... initialize data in the test database ...
    }

    public void Dispose()
    {
        // ... clean up test data from the database ...
    }

    public SqlConnection Db { get; private set; }
}

public class MyDatabaseTests : IClassFixture<DatabaseFixture>
{
    DatabaseFixture fixture;

    public MyDatabaseTests(DatabaseFixture fixture)
    {
        this.fixture = fixture;
    }


    [Fact]
    public async Task GetTest()
    {
        // ... write tests, using fixture.Db to get access to the SQL Server ...
        // ... 在這裡使用註入 的 DatabaseFixture
    }
}

Singleton Sample

這裡以一個對 Controller 測試的測試為例

  1. 自定義 Fixture

        /// <summary>
        /// A test fixture which hosts the target project (project we wish to test) in an in-memory server.
        /// </summary>
        public class TestStartupFixture : IDisposable
        {
            private readonly IWebHost _server;
            public IServiceProvider Services { get; }
    
            public HttpClient Client { get; }
    
            public string ServiceBaseUrl { get; }
    
            public TestStartupFixture()
            {
                var builder = WebHost.CreateDefaultBuilder()
                    .UseUrls($"http://localhost:{GetRandomPort()}")
                    .UseStartup<TestStartup>();
    
                _server = builder.Build();
                _server.Start();
    
                var url = _server.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First();
                Services = _server.Services;
                ServiceBaseUrl = $"{url}/api/";
    
                Client = new HttpClient()
                {
                    BaseAddress = new Uri(ServiceBaseUrl)
                };
    
                Initialize();
            }
    
            /// <summary>
            /// TestDataInitialize
            /// </summary>
            private void Initialize()
            {
                // ...
            }
    
            public void Dispose()
            {
                Client.Dispose();
                _server.Dispose();
            }
    
            private static readonly Random Random = new Random();
    
            private static int GetRandomPort()
            {
                var activePorts = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(_ => _.Port).ToList();
    
                var randomPort = Random.Next(10000, 65535);
    
                while (activePorts.Contains(randomPort))
                {
                    randomPort = Random.Next(10000, 65535);
                }
    
                return randomPort;
            }
        }
  2. 自定義Collection

        [CollectionDefinition("TestCollection")]
        public class TestCollection : ICollectionFixture<TestStartupFixture>
        {
        }
  3. 自定義一個 TestBase

        [Collection("TestCollection")]
        public class ControllerTestBase
        {
            protected readonly HttpClient Client;
            protected readonly IServiceProvider ServiceProvider;
    
            public ControllerTestBase(TestStartupFixture fixture)
            {
                Client = fixture.Client;
                ServiceProvider = fixture.Services;
            }
        }
  4. 需要依賴註入的Test類寫法

    public class AttendancesTest : ControllerTestBase
    {
        public AttendancesTest(TestStartupFixture fixture) : base(fixture)
        {
        }

        [Fact]
        public async Task GetAttendances()
        {
            var response = await Client.GetAsync("attendances");
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            response = await Client.GetAsync("attendances?type=1");
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        }
    }

Reference

Contact

如果您有什麼問題,歡迎隨時聯繫我

Contact me: [email protected]


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  •  上次接手一個項目需要整合公眾號、小程式以及APP的用戶,查閱了微信文檔以及一些作者的文章,中間踩了不少坑,在此記錄一下解決的流程。 要點  實現統一信息的有以下幾點:  1. 在微信開放平臺綁定需要統一信息的應用;  2. 公眾號採用以snsapi_user ...
  • 二叉樹的深度: 輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。 思路: 1.非遞歸層序遍歷 2.使用輔助隊列,根結點先入隊列 3. 迴圈判斷隊列是否為空,如果不為空就繼續迴圈隊列裡面的每個結點 4. 迴圈隊列時,當前當前結點出... ...
  • 題目 一直沒有頭緒的一道題 明明只有普及-難度 看了看題解用的大多是方程和Fibonacci 於是更加懵逼了。。。 今天立志AC此題 結果用大模擬還真過了 說一下思路 然而並沒有思路 按照題意敲代碼 不妨設第二站上下車了k人 分別統計每一站a和k的繫數 1、2、n站特殊處理 然後求出k,代入x站中輸 ...
  • Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-f8IeEI/MYSQL-python/錯誤無法安裝python第三方庫需要安裝libmysqlclient-devapt-get inst... ...
  • 內容 本文對JDK1.7下使用segmentShift和segmentMask求解ConcurrentHashMap鍵值對在Segment[]中的下標值進行了探究和論證。 適合人群 ​ Java進階 說明 轉載請註明出處,尊重筆者的勞動成果。 推薦閱讀 探究HashMap線性不安全(二)——鏈表成環 ...
  • 題意 "題目鏈接" Sol 只要知道“迴文連續子串”就能做了吧。。 想要滿足這個條件,肯定是不能出現$aa$或$aba$這種情況 如果沒有$S$的限制,答案為$K (K 1) \prod_{i = 3}^n (k 2)$ 如果有$S$的限制就除一個$K$ 然而考場上沒註意到會乘爆long long於 ...
  • 主要內容:1. 模塊的簡單認識2. collections模塊3. time時間模塊4. random模塊5. os模塊6. sys模塊 一. 模塊的簡單認識什麽是模塊. 模塊就是我們把裝有特定功能的代碼進行歸類的結果. 從代碼編寫的單位來看我們的程式, 從小到大的順序: 一條代碼 < 語句句塊 < ...
  • 直接上代碼 HTML頁面代碼: controller.js代碼 webapi代碼: 有疑問歡迎交流。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...