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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...