自動化測試數據生成:Asp.Net Core單元測試利器AutoFixture詳解

来源:https://www.cnblogs.com/ruipeng/p/18163423
-Advertisement-
Play Games

引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...


引言

在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"

什麼是AutoFixture?

AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高可維護性。它的主要目標是讓開發人員專註於被測試的內容,而不是如何設置測試場景,通過更容易地創建包含測試數據的對象圖,從而實現這一目標。

AutoFixture 可以幫助開發人員自動生成測試數據,減少手動設置測試數據的工作量,提高單元測試的效率和可維護性。通過自動生成對象,開發人員可以更專註於編寫測試邏輯,而不必花費大量精力在準備測試數據上。

其實和Bogus相比,AutoFixture更強大的地方在於可以自動化設置對象的值,當類發生變化時如屬性名或者類型更改,我們不需要去進行維護,AutoFixture可以自動適應Class的變化。

AutoFixture與流行的 .NET 測試框架(如 NUnitxUnit)可以無縫集成。

AutoFixture實戰

我們在創建xUnit單元測試項目dotNetParadise.AutoFixture

安裝依賴

創建完項目之後我們首先要安裝Nuget

PM> NuGet\Install-Package AutoFixture -Version 4.18.1

初始化

AutoFixture的使用是從一個Fixture的實例對象開始的

var fixture = new Fixture();

接下來我們先創建一個測試類來學一下AutoFixture的使用

public class AutoFixtureStaffTest
{
    private readonly IFixture _fixture;
    public AutoFixtureStaffTest()
    {
        _fixture = new Fixture();
    }
}

實戰

我們之前的測試項目創建了Sample.ApiSample.Repository兩個類庫來做我們被測試的項目,本章繼續使用Sample.Repository來演示AutoFixture的使用。

dotNetParadise.AutoFixture 測試項目添加Sample.Repository的項目引用

Sample.Repository中我們有一個Staff的實體對象,繼續用作我們的測試

public class Staff
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int? Age { get; set; }
    public List<string>? Addresses { get; set; }
    public DateTimeOffset? Created { get; set; }
    public void Update(Staff staff)
    {
        this.Name = staff.Name;
        this.Email = staff.Email;
        this.Age = staff.Age;
        this.Addresses = staff.Addresses;
        Created = staff.Created;
    }
}

屬性賦值

   [Fact]
   public void Staff_SetProperties_ValuesAssignedCorrectly()
   {
       //Arrange
       Staff staff = new Staff();
       //生成Int類型
       staff.Id = _fixture.Create<int>();
       //生成string 類型
       staff.Name = _fixture.Create<string>();
       //生成DateTimeOffset類型
       staff.Created = _fixture.Create<DateTimeOffset>();
       //生成 List<string>?
       staff.Addresses = _fixture.CreateMany<string>(Random.Shared.Next(1, 100)).ToList();
       //Act
       //...省略
       // Assert
       Assert.NotNull(staff); // 驗證 staff 對象不為 null

       // 驗證 staff.Id 是 int 類型
       Assert.IsType<int>(staff.Id);

       // 驗證 staff.Name 是 string 類型
       Assert.IsType<string>(staff.Name);

       // 驗證 staff.Created 是 DateTimeOffset? 類型
       Assert.IsType<DateTimeOffset>(staff.Created);

       // 驗證 staff.Addresses 是 List<string> 類型
       Assert.IsType<List<string>>(staff.Addresses);

       // 驗證 staff.Addresses 不為 null
       Assert.NotNull(staff.Addresses);

       // 驗證 staff.Addresses 中的元素數量在 1 到 100 之間
       Assert.InRange(staff.Addresses.Count, 1, 100);
   }

示例中用到 AutoFixture 提供的的方法隨機分配隨機值,上面的示例中用到使用到了兩個方法

Create<T>方法

  • 用於生成一個指定類型 T 的實例。它會自動填充對象的屬性和欄位,以便創建一個完整的對象實例。
  • 這個方法通常用於生成單個對象實例,適用於需要單個對象作為測試數據的情況。
  • 當調用 Create<T> 方法時,AutoFixture 會根據 T 類型的構造函數、屬性和欄位來自動生成合適的值,以確保對象實例的完整性和一致性。

CreateMany<T>方法

  • 用於生成多個指定類型 T 的實例,通常用於生成集合或列表類型的測試數據。
  • 這個方法允許你指定要生成的實例數量,並返回一個包含這些實例的 IEnumerable 集合。
  • 當調用 CreateMany<T> 方法時,AutoFixture 會根據 T 類型的構造函數、屬性和欄位來生成指定數量的對象實例,以便填充集合或列表。

T包括基本類型(如 stringint)、自定義對象等

Create<T>構造對象

上面的例子我們自己實例化的對象然後對對象挨個賦值,目的是讓大家對AutoFixture的使用有一個初步的認識,上面也解釋到了Create<T>的泛型參數T可以是自定義的對象,那麼我們來簡化一下上面的示例

[Fact]
public void Staff_ObjectCreation_ValuesAssignedCorrectly()
{
    // Arrange
    Staff staff = _fixture.Create<Staff>(); // 使用 AutoFixture 直接創建 Staff 對象

    // Act
    //...省略

    // Assert
    Assert.NotNull(staff); // 驗證 staff 對象不為 null

    // 驗證 staff.Id 是 int 類型
    Assert.IsType<int>(staff.Id);

    // 驗證 staff.Name 是 string 類型
    Assert.IsType<string>(staff.Name);

    // 驗證 staff.Created 是 DateTimeOffset? 類型
    Assert.IsType<DateTimeOffset>(staff.Created);

    // 驗證 staff.Addresses 是 List<string> 類型
    Assert.IsType<List<string>>(staff.Addresses);

    // 驗證 staff.Addresses 不為 null
    Assert.NotNull(staff.Addresses);

    // 驗證 staff.Addresses 中的元素數量在 1 到 100 之間
    Assert.InRange(staff.Addresses.Count, 1, 100);
}

修改後的例子中,我們使用 AutoFixtureCreate<Staff>() 方法直接創建了一個 Staff 對象,而不是手動為每個屬性賦值。這樣可以更簡潔地生成對象實例。

數據驅動測試

在正常的同一個測試方法中使用不同的輸入數據進行測試時,通常都是基於 Theory 屬性配合InlineData或者MemberData來完成的,有了AutoFixture之後數據也不用我們自己造了,來看一下實戰入門

第一步Nuget安裝依賴

PM> NuGet\Install-Package AutoFixture.Xunit2 -Version 4.18.1

[AutoData]屬性

[Theory, AutoData]
public void Staff_Constructor_InitializesPropertiesCorrectly(
    int id, string name, string email, int? age, List<string> addresses, DateTimeOffset? created)
{
    // Act
    var staff = new Staff { Id = id, Name = name, Email = email, Age = age, Addresses = addresses, Created = created };

    // Assert
    Assert.Equal(id, staff.Id);
    Assert.Equal(name, staff.Name);
    Assert.Equal(email, staff.Email);
    Assert.Equal(age, staff.Age);
    Assert.Equal(addresses, staff.Addresses);
    Assert.Equal(created, staff.Created);
}

通過 AutoData 方法,測試方法的參數化設置變得更加簡單和高效,使得編寫參數化測試方法變得更加容易。

[InlineAutoData]屬性

如果我們有需要提供的特定化參數,可以用[InlineAutoData]屬性,具體使用可以參考如下案例

    [Theory]
    [InlineAutoData(1)]
    [InlineAutoData(2)]
    [InlineAutoData(3)]
    [InlineAutoData]
    public void Staff_ConstructorByInlineData_InitializesPropertiesCorrectly(
     int id, string name, string email, int? age, List<string> addresses, DateTimeOffset? created)
    {
        // Act
        var staff = new Staff { Id = id, Name = name, Email = email, Age = age, Addresses = addresses, Created = created };

        // Assert
        Assert.Equal(id, staff.Id);
        Assert.Equal(name, staff.Name);
        Assert.Equal(email, staff.Email);
        Assert.Equal(age, staff.Age);
        Assert.Equal(addresses, staff.Addresses);
        Assert.Equal(created, staff.Created);
    }

自定義對象屬性值

AutoFixtureBuild 方法結合 With 方法可以用於自定義對象的屬性值

    [Fact]
    public void Staff_SetCustomValue_ShouldCorrectly()
    {
        var staff = _fixture.Build<Staff>()
            .With(_ => _.Name, "Ruipeng")
            .Create();
        Assert.Equal("Ruipeng", staff.Name);
    }

禁用屬性自動生成

AutoFixture 中,可以使用 OmitAutoProperties 方法來關閉自動屬性生成,從而避免自動生成屬性值。這在需要手動設置所有屬性值的情況下很有用。

    [Fact]
    public void Test_DisableAutoProperties()
    {
        // Arrange
        var fixture = new Fixture();
        var sut = fixture.Build<Staff>()
                         .OmitAutoProperties()
                         .Create();

        // Assert
        Assert.Equal(0, sut.Id); // 驗證 Id 屬性為預設值 0
        Assert.Null(sut.Name); // 驗證 Name 屬性為 null
        Assert.Null(sut.Email); // 驗證 Email 屬性為 null
        Assert.Null(sut.Age); // 驗證 Age 屬性為 null
        Assert.Null(sut.Addresses); // 驗證 Addresses 屬性為 null
        Assert.Null(sut.Created); // 驗證 Created 屬性為 null
    }

Do 方法執行自定義操作

Do 方法是 AutoFixture 中用於執行操作的方法,通常結合 Build 方法一起使用,用於在構建對象時執行自定義操作。讓我詳細解釋一下 Do 方法的用法和作用:

主要特點:

  • 執行操作:Do 方法允許在對象構建過程中執行自定義操作,例如向集合添加元素、設置屬性值等。
  • 鏈式調用:可以通過鏈式調用多個 Do 方法,依次執行多個操作。
  • 靈活定製:通過 Do 方法,可以在對象構建過程中靈活地定製對象的屬性值或執行其他操作。
    使用方法:
  • 結合 Build 方法:通常與 Build 方法一起使用,用於為對象構建器執行操作。
  • 執行自定義操作:在 Do 方法中傳入一個 lambda 表達式,可以在 lambda 表達式中執行需要的操作。
  • 鏈式調用:可以多次調用 Do 方法,實現多個操作的順序執行。
   [Fact]
   public void Test_UpdateMethod()
   {
       // Arrange
       var fixture = new Fixture();
       var staff1 = fixture.Create<Staff>();
       var staff2 = fixture.Create<Staff>();

       // 使用 Do 方法執行自定義操作
       var staff3 = fixture.Build<Staff>()
                                 .Do(x => staff1.Update(staff2))
                                 .Create();

       // Assert
       Assert.Equal(staff2.Name, staff1.Name); // 驗證 Name 是否更新
       Assert.Equal(staff2.Email, staff1.Email); // 驗證 Email 是否更新
       Assert.Equal(staff2.Age, staff1.Age); // 驗證 Age 是否更新
       Assert.Equal(staff2.Addresses, staff1.Addresses); // 驗證 Addresses 是否更新
       Assert.Equal(staff2.Created, staff1.Created); // 驗證 Created 是否更新
   }

創建三個對象,在第三個創建過程中把第一個的對象屬性用第二個對象的屬性覆蓋。

Customize Type 自定義類型

使用自定義類型構建器來執行複雜的初始化,並且保證了創建多個相同的實例中要保持一致的自定義行為。

首先我們可以在我們的測試類構造函數中定義一個自定義規則

    public AutoFixtureStaffTest()
    {
        _fixture = new Fixture();
        _fixture.Customize<Staff>(composer => composer.With(x => x.Email, "[email protected]"));
    }

比如我設置了所有的 email 都叫[email protected]

    [Fact]
    public void Test_StaffNameIsJohnDoe()
    {
        // Arrange
        Staff staff = _fixture.Create<Staff>();

        // Act

        // Assert
        Assert.Equal("[email protected]", staff.Email);
    }

這個位置大概得思想就是這樣,保證用到的多實例都有相同的行為,可以參考:
使用 AutoFixture 自定義類型的生成器

Auto-Mocking with Moq

第一步安裝Nuget

PM> NuGet\Install-Package AutoFixture.AutoMoq -Version 4.18.1

    [Fact]
    public async Task Repository_Add_ShouleBeSuccess()
    {
        _fixture.Customize(new AutoMoqCustomization());
        var repoMock = _fixture.Create<IStaffRepository>();
        Assert.NotNull(repoMock);
    }

創建 Fixture 實例並使用 AutoMoqCustomization 進行定製化,以便自動模擬 Moq 對象。
使用 Create<IInterface>() 方法創建一個可分配給 IInterface 介面的模擬實例。

Auto-configured Mocks

官網示例:

fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
fixture.Inject<int>(1234);

var document = fixture.Create<IDocument>();
Console.WriteLine(document.Id); // 1234

當將 ConfigureMembers = true 添加到 AutoMoqCustomization 中時,不僅會作為自動模擬容器,還會自動配置所有生成的模擬對象,使其成員返回 AutoFixture 生成的值。
使用 Inject<int>(1234) 將整數值 1234註入到 Fixture 中。
使用 Create<IDocument>() 創建一個 IDocument 介面的實例,並輸出其 Id 屬性值。

更多

Moq 框架中存在一些限制,其中自動配置模式無法設置具有 ref參數的方法,並且也無法配置泛型方法。然而,您可以使用 ReturnsUsingFixture 擴展方法輕鬆地設置這些方法。

官網示例:

converter.Setup(x => x.Convert<double>("10.0"))
         .ReturnsUsingFixture(fixture);

在這個示例中,使用 ReturnsUsingFixture 擴展方法手動設置了一個名為 Convert 的泛型方法的行為。
當調用 Convert 方法並傳入字元串"10.0" 時,ReturnsUsingFixture方法將使用fixture生成的值作為返回值。 通過使用ReturnsUsingFixture擴展方法,您可以繞過Moq框架的限制,手動設置具有ref` 參數或泛型方法的行為,以滿足特定的測試需求.

最後

AutoFixture就像是一個自動數據生成器,讓我們的單元測試變得更簡單、更高效。通過使用它,我們可以輕鬆地創建測試數據,專註於寫好測試邏輯,而不用為數據準備的瑣事煩惱.


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

-Advertisement-
Play Games
更多相關文章
  • 一般來說Maven都是配合著idea一起使用,下載依賴速度慢就去網上找個鏡像配置一下,但總會遇到莫名其妙的問題,比如鏡像源不生效、Error reading file pom.xml等等。今天詳細講解一下maven配置文件settings.xml的配置方法。 小知識 maven的配置文件存在於兩個地 ...
  • 1. JUnit 最佳實踐指南 原文: https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/ 我假設您瞭解 JUnit 的基礎知識。 如果您沒有基礎知識,請首先閱讀(已針 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...