.NET單元測試使用AutoFixture按需填充的幾種方式和最佳實踐

来源:https://www.cnblogs.com/vipwan/p/18311419
-Advertisement-
Play Games

AutoFixture是一個.NET庫,旨在簡化單元測試中的數據設置過程。通過自動生成測試數據,它幫助開發者減少測試代碼的編寫量,使得單元測試更加簡潔、易讀和易維護。AutoFixture可以用於任何.NET測試框架,如xUnit、NUnit或MSTest。 預設情況下AutoFixture生成的字 ...


AutoFixture是一個.NET庫,旨在簡化單元測試中的數據設置過程。通過自動生成測試數據,它幫助開發者減少測試代碼的編寫量,使得單元測試更加簡潔、易讀和易維護。AutoFixture可以用於任何.NET測試框架,如xUnit、NUnit或MSTest。

預設情況下AutoFixture生成的欄位值很多時候都滿足不了測試需求,比如:

public class User
{
	public int Id { get; set; }
	public string Name { get; set; } = null!;
	[EmailAddress]
	public string? Email { get; set; }
	[StringLength(512)]
	public string? Address { get; set; }
	public DateTime CreatedAt { get; set; } = DateTime.Now;
}

如果直接使用 Create<T>()生成的User對象,他會預設給你填充Id為隨機整數,Name和Email為一串Guid,顯然這裡的郵箱地址生成就不能滿足要求,並不是一個有效的郵箱格式

那麼如何讓AutoFixture按需生成有效的測試數據呢?方法其實有好幾種:

方法1:直接定製
var fixture = new Fixture();
fixture.Customize<User>(c => c
    .With(x => x.Email, "特定值")
    .Without(x => x.Id));

這裡,With方法用於指定屬性的具體值,而Without方法用於排除某些屬性不被自動填充。

方法2:使用匿名函數

這在需要對生成的數據進行更複雜的操作時非常有用。

var fixture = new Fixture();
fixture.Customize<User>(c => c.FromFactory(() => new User
{
    Email = "通過工廠方法生成",
}));
方法3:實現ICustomization介面

對於更複雜的定製需求,可以通過實現ICustomization介面來創建一個定製化類。這種方法的好處是可以重用定製邏輯,並且使得測試代碼更加整潔。

public class MyCustomClassCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<User>(c => c
            .With(x => x.Email, "自定義值")
            .Without(x => x.Id));
    }
}
// 使用定製化
var fixture = new Fixture();
fixture.Customize(new MyCustomClassCustomization());
方法4:使用Build<T>方法

Build<T>方法提供了一種鏈式調用的方式來定製類型的生成規則,這在只需要對單個對象進行簡單定製時非常方便。

var myCustomObject = fixture.Build<User>()
                            .With(x => x.Email, $"{Guid.NewId()}@example.com")
                            .Without(x => x.Id)
                            .Create();

最佳實踐:

這裡以xunit測試框架為例,
我們需要提前引用AutoFixture,AutoFixture.Xunit2庫,實現一個UserAutoDataAttribute類,繼承自InlineAutoDataAttribute 重寫GetData方法,大致代碼如下:

public  class UserAutoDataAttribute : InlineAutoDataAttribute
    {
        public UserAutoDataAttribute(params object[] values) : base(values)
        {
            ArgumentNullException.ThrowIfNull(values[0]);
        }

        public override IEnumerable<object[]> GetData(MethodInfo testMethod)
        {
            var fixture = new Fixture();
            //這裡使用上面的4種方式的一種,亦或者根據自身情況定製!
            var user = fixture.Build<User>()
                 //.With(x => x.Id, 0)
                 .Without(x => x.Id) //ID需要排除因為EFCore需要插入時自動生成
                 .With(x => x.Email, $"{Uuid7.NewUuid7()}@example.com") //郵箱地址,需要照規則生成
                 .Create();
            yield return new object[] { Values[0], user };
        }
    }

下麵是一個測試用例,需要填充db,和一個自動生成的User參數

public class UnitOfWorkTests(ITestOutputHelper output)
{
	[Theory]
	[UserAutoData(1)]
	[UserAutoData(2)]
	public async Task MyUnitOfWorkTest(int db, User user)
	{
		var services = new ServiceCollection();
		services.AddLogging();
		services.AddDbContext<TestDbContext>(options =>
		 {
                    options.UseInMemoryDatabase($"test-{db}");
		});
		services.AddUnitOfWork<TestDbContext>();

		var provider = services.BuildServiceProvider();
		var uow = provider.GetRequiredService<IUnitOfWork<TestDbContext>>();

		//add user
		await uow.GetRepository<User>().InsertAsync(user);
		await uow.SaveChangesAsync();

		// select user
		var user2 = await uow.GetRepository<User>().FindAsync(1);
		Assert.NotNull(user2);

		// delete user
		uow.GetRepository<User>().Delete(1);
		var row = await uow.SaveChangesAsync();

		Assert.Equal(1, row);

		// select user
		user2 = await uow.GetRepository<User>().GetFirstOrDefaultAsync(x => x.Id == 1);
		Assert.Null(user2);
	}
}

如果你已經習慣編寫單元測試,但還沒有使用AutoFixture,那麼推薦你嘗試一下,也許你也會喜歡上TA


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

-Advertisement-
Play Games
更多相關文章
  • 力扣 704.二分查找 給定一個n個元素的有序的(升序)整型數組nums和一個目標值target,寫一個函數搜索nums中的target,如果目標值存在返回小標,否則返回-1。 思路:二分查找法,定義左右邊界[left,right);不斷取中值縮小查找範圍。 class Solution{ publ ...
  • 前言 本人在配置VsCode C++開發環境時,查看了很多的博客,內容參差不齊,尤其是關於json文件的配置,繞得人頭很暈,最終還是通過閱讀官方文檔,結合部分博客的指引,完成了環境的配置,在此記錄本人的配置過程,希望能幫助到大家。事先聲明,本文的內容大量引自Vs Code官方的文章:https:// ...
  • 一:背景 1. 講故事 最新版本 1.2402.24001.0 的WinDbg真的讓人很興奮,可以將自己偽裝成 GDB 來和遠程的 GDBServer 打通來實現對 Linux 上 .NET程式進行調試,這樣就可以繼續使用熟悉的WinDbg 命令,在這個版本中我覺得 WinDbg 不再是 WinDb ...
  • 前置 預先連接 可以從連接器創建預先連接,並可以放置在ItemContainer或Connector上(如果AllowOnlyConnectors為false)。 預先連接的Content可以使用ContentTemplate進行自定義。如果EnablePreview為true,PreviewTar ...
  • 現如今大模型遍地都是,OpenAI的ChatGPT,Meta的Llama(羊駝),Anthropic的Claude,Microsoft的Phi3,Google的Gemini...... 怎麼都是國外的???嗯,國內也有,比如騰訊有混元大模型,位元組跳動有豆包大模型等等。 不過這不是今天的重點,這寫國內 ...
  • 前兩天發了一篇關於模式匹配的文章,鏈接地址,有小伙伴提到使用.NET6沒法體驗 C#新特性的疑問, 其實呢只要本地的SDK源代碼編譯器能支持到的情況下(直接下載VS2022或者VS的最新preview版本) 只需要做很小的改動就可以支持的. 目前仍然還有一些小伙伴因為歷史原因可能還在寫.NET Fr ...
  • 字元串轉換為數字int.TryParse() bool success = int.TryParse("300",out int b); Console.WriteLine(success); // 輸出為 true Console.WriteLine(b); //輸出為 300 字元串里的“300 ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
一周排行
    -Advertisement-
    Play Games
  • 前言 推薦一款基於.NET 8、WPF、Prism.DryIoc、MVVM設計模式、Blazor以及MySQL資料庫構建的企業級工作流系統的WPF客戶端框架-AIStudio.Wpf.AClient 6.0。 項目介紹 框架採用了 Prism 框架來實現 MVVM 模式,不僅簡化了 MVVM 的典型 ...
  • 先看一下效果吧: 我們直接通過改造一下原版的TreeView來實現上面這個效果 我們先創建一個普通的TreeView 代碼很簡單: <TreeView> <TreeViewItem Header="人事部"/> <TreeViewItem Header="技術部"> <TreeViewItem He ...
  • 1. 生成式 AI 簡介 https://imp.i384100.net/LXYmq3 2. Python 語言 https://imp.i384100.net/5gmXXo 3. 統計和 R https://youtu.be/ANMuuq502rE?si=hw9GT6JVzMhRvBbF 4. 數 ...
  • 本文為大家介紹下.NET解壓/壓縮zip文件。雖然解壓縮不是啥核心技術,但壓縮性能以及進度處理還是需要關註下,針對使用較多的zip開源組件驗證,給大家提供個技術選型參考 之前在《.NET WebSocket高併發通信阻塞問題 - 唐宋元明清2188 - 博客園 (cnblogs.com)》講過,團隊 ...
  • 之前寫過兩篇關於Roslyn源生成器生成源代碼的用例,今天使用Roslyn的代碼修複器CodeFixProvider實現一個cs文件頭部註釋的功能, 代碼修複器會同時涉及到CodeFixProvider和DiagnosticAnalyzer, 實現FileHeaderAnalyzer 首先我們知道修 ...
  • 在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明瞭圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 在 C# 中使用 RabbitMQ 通過簡訊發送重置後的密碼到用戶的手機號上,你可以按照以下步驟進行 1.安裝 RabbitMQ 客戶端庫 首先,確保你已經安裝了 RabbitMQ 客戶端庫。你可以通過 NuGet 包管理器來安裝: dotnet add package RabbitMQ.Clien ...
  • 1.下載 Protocol Buffers 編譯器(protoc) 前往 Protocol Buffers GitHub Releases 頁面。在 "Assets" 下找到適合您系統的壓縮文件,通常為 protoc-{version}-win32.zip 或 protoc-{version}-wi ...
  • 簡介 在現代微服務架構中,服務發現(Service Discovery)是一項關鍵功能。它允許微服務動態地找到彼此,而無需依賴硬編碼的地址。以前如果你搜 .NET Service Discovery,大概率會搜到一大堆 Eureka,Consul 等的文章。現在微軟為我們帶來了一個官方的包:Micr ...
  • ZY樹洞 前言 ZY樹洞是一個基於.NET Core開發的簡單的評論系統,主要用於大家分享自己心中的感悟、經驗、心得、想法等。 好了,不賣關子了,這個項目其實是上班無聊的時候寫的,為什麼要寫這個項目呢?因為我單純的想吐槽一下工作中的不滿而已。 項目介紹 項目很簡單,主要功能就是提供一個簡單的評論系統 ...