只有累積,沒有奇蹟

2019年4月17日 星期三

[UnitTest] 使用 Fluent Assertions 增加單元測試碼可讀性

前言
過去在撰寫單元測試代碼時都是使用 NUnit 內建的 Assert.AreEqual 來驗證是否符合預期,雖然早已聽過 Fluent Assertions 盛名但並未實際使用過,直到最近在與同事討論時同事大推發現真的很不錯,讓戴碼的可能性增加不少,想起之前上 91 Training 時不斷強調測試代碼可讀性的重要性,這一篇就來簡單介紹 Flnent Asserentions 的安裝與使用若有問題或是錯誤的地方歡迎各位高手給予指導

安裝 Fluent Assertions
Fluent Assertion 支援 .NET Framework 與 .NET Core,常用的測試框架像是 NUnit、MSTest、xUnit 等都支援,一開始在 Visual Studio 2019 建立名稱叫做 FluentAssertionsConsoleApp 的 ConsoleApp專案,接著在專案 Program.cs 輸入要測試的程式碼 Add 方法,如下所示
  1. public class TestMethod
  2. {
  3. public int Add(int numberOne, int numberTwo)
  4. {
  5. return numberOne + numberTwo;
  6. }
  7. }
接著要建立測試專案,在 Visual Studio 2019 建立專案介面有做調整,可以透過搜尋輸入框及下拉選單過找到想要建立的專案範本,這陣子使用操作上覺得挺方便的,如下圖所示,在搜尋框輸入 NUnit 選定 NUmit 專案並按下一步 
建立完畢 NUnit 測試專案後,下一步是在測試專案安裝 Fluent Assertions nuget 套件,步驟如下
Step 1 : 按下 CTRL + Q 輸入 Nuget,開啟 nuget 
Step 2 : 在 Nuget Package Mnager 輸入 FluentAssertions,目前最新版為 5.6.0 按下安裝
安裝完畢後確認測試專案有 Fluent Assertional 即代表安裝成功

測試代碼
接著要開始測試 TestMethod 中的 Add 方法,開始嘗試用 Fluent Asserentions 語法寫測試,代碼如下
  1. using FluentAssertions;
  2. using FluentAssertionsConsoleApp;
  3. using NUnit.Framework;
  4.  
  5. namespace Tests
  6. {
  7. public class Tests
  8. {
  9. [Test]
  10. public void AddTest_Using_FluentAssertions()
  11. {
  12. var testMethod = new TestMethod();
  13. var actual = testMethod.Add(2, 4);
  14. actual.Should().Be(6);
  15. }
  16. }
  17. }
使用 Fluent Assertions 寫法後代碼變得容易理解許多,actual.Should().Be(6) 用口語化解釋為 " 測試的結果應該為 6 ",另外 Be 方法也提供 Because 參數,加上後可以讓語句與閱讀上更加通順,加上 Because 後代碼如下
  1. [Test]
  2. public void AddTest_Using_FluentAssertions_Becasue()
  3. {
  4. var testMethod = new TestMethod();
  5. var actual = testMethod.Add(2, 2);
  6. actual.Should().Be(4, because:"2+2=4");
  7. }
測試案例加上 because 後當測試失敗時,可以透過錯誤訊息內容讓你或是你的團隊成員更容易理解測試的目的,測試失敗的 Testcase 如下
透過 Resharper 可以看到 Should 擴充方法內容如下,Should 與 Be 都是 FluentAssertions 針對 int 型別定義的擴充方法 ( Extension Methods ),透過 F12 後可以看到內容

  1. /// <summary>
  2. /// Returns an <see cref="T:FluentAssertions.Numeric.NumericAssertions`1" /> object that can be used to assert the
  3. /// current <see cref="T:System.Int32" />.
  4. /// </summary>
  5. [Pure]
  6. public static NumericAssertions<int> Should(this int actualValue)
  7. {
  8. return new NumericAssertions<int>((object) actualValue);
  9. }
擴充方法可以參考 MSDN 說明 : 傳送門,擴充方法可以在很多地方看到像是 LINQ 中的 Where ,針對集合物件做篩選的動作在回傳 IEnumerable<T>,在 Fluent Assertions 針對現有類別加入方法,方便使用 Should、Be 或是其他語法,方便在單元測試中撰寫,以下列出一些常用的方式,

  1. public void TestBasicMethod()
  2. {
  3. // object
  4. object obj = null;
  5. obj.Should().BeNull("because the obj is null");
  6. obj.Should().NotBeNull();
  7.  
  8. // string
  9. var something = "something";
  10. something.Should().BeEmpty();
  11. something.Should().NotBeEmpty();
  12.  
  13. // datetime
  14. var time= new DateTime();
  15. time.Should().HaveYear(2019);
  16. time.Should().HaveDay(4);
  17. time.Should().HaveMonth(3);
  18. time.Should().HaveHour(22);
  19. time.Should().HaveMinute(15);
  20. time.Should().HaveSecond(0);
  21.  
  22. // dictionary
  23. var dic = new Dictionary<int, string>()
  24. {
  25. {1, "Marcus"},
  26. {2, "Flash"},
  27. {3, "Neil"}
  28. };
  29. dic.Should().NotBeEmpty();
  30. // type
  31. something.Should().BeOfType<string>("because a {0} is set", typeof(string));
  32. something.Should().BeOfType(typeof(string), "because a {0} is set", typeof(string));
  33.  
  34. // equal
  35. string otherObject = "whatever";
  36. something.Should().Be(otherObject, "because they have the same values");
  37. something.Should().NotBe(otherObject);
  38.  
  39. // exception
  40. something.Should().BeOfType<Exception>()
  41. .Which.Message.Should().Be("Other Message");
  42. }

如果您希望測試代碼更容易理解,建議你可以使用 Fluent Assertion Library 來協助撰寫單元測試,更多的測試語法可以參考官方文件說明,這篇就簡單介紹 Fluent Assertion,日後如果有遇過不錯的寫法也會在一併分享給各位,Happy Coding :)

參考
Fluent Assertions 
讓單元測試代碼更好寫、好讀:Fluent Assertions

Related Posts:

  • [UnitTest] 如何測試目標方法中 Guid 型別的代碼 ?情境 如果要產生一個亂數時很常會想到 Guid 方法解決,在 C# 使用 Guid 的方式相當簡單僅要透過  Guid.NewGuid  靜態方法產生一組 Guid 使用,在目前公司很常看到使用 Guid 作為識別碼,今天在重構舊代碼時忽然想到如果遇到 Guid 該如何進行加上單元測試,以下就目前想到的解法進行測試與說明,如果各位高手們有更好的方法歡迎高抬貴手一起討論研究。 解決方案 寫個簡單的 Sa… Read More
  • [UnitTest] Reflect.cs not found in NUnit問題 最近在新的專案寫 UnitTest 過程中,執行完後 Visual Studio 卻跳出 Source Not Fount : Reflect.cs not found 錯誤,但單元測試還是可以成功,如下圖 且透過 debug UnitTest 時發現測試的值也沒問題,經搜尋後發現是 Visual Studio 2017 IDE 設定問題,將,這篇文章簡單紀錄處理問題過程 處理方式 釐清問題 按下… Read More
  • [UnitTest] Visual Studio 2017 新增單元測試時沒有 NUnit 選項 ?前言 新筆電總是讓人充滿驚喜,在使用上除了要重新安裝常用的開發工具外,像是 Visual Studio & SQL Server..等必須工具,還有些常用的套件與小工具也要一併安裝,NUnit 是蠻常用的 Test Framwroek 之一,在寫測試時在要測試的 method 下按下右鍵 create Unit Tests,選擇要使用測試的 Test Framework 即可,在測試專案中預設只有 MSTest 選項,如果需要 NUnit… Read More
  • [UnitTest] Visual Studio 2017 按右鍵無法建立單元測試 ? 問題 最近心血來潮使用家中舊電腦小白寫 Code,在練習測試中發現竟然有點怪異,在要測試的 method 按下右鍵沒有 建立單元測試 Create Unit Test 選項,但相同練習專案拿到公司筆電就是正常的,經比對後發現舊筆電 Visual Studio 版本少安裝測試功能,以下簡單紀錄解決問題的過程 解決方案 在 Visual Studio 2017 早期版本這是已知問題,有開發者在 vs community 回報給開… Read More
  • [UnitTest] ASP.NET Core 2.2 測試專案中的版本衝突 問題  這幾天專案某項功能接近尾聲,要替其核心 ASP.NET Core 專案加上單元測試專案,加入後按下建置發現跳出 Error 錯誤訊息  "CS1705 Assembly 'xxxx, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' uses 'Microsoft.Extensions.Logging.Abstractions, Version=2.… Read More

0 意見:

張貼留言

Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com