只有累積,沒有奇蹟

2019年1月20日 星期日

[UnitTest] NUnit 參數測試 - 使用 TestCase、TestCaseSource

前言
上一篇 NUnit 入門教學 簡單介紹如何使用 NUnit 撰寫單元測試,但在實務上在寫單元測試時不會那麼單純,舉例來說如果要針對某個 method 進行種不同情境的測試,僅差在不同的參數來多次驗證結果
NUnit 官方文件中有提供很多好用的方法像是 TestCaseTestCaseSource 等方式可以解決此問題,以下會簡單分享小小研究後的說明與差異性,依據適合的情境使用相對應的方法

解決方案
要驗證的 sample Code 如下,Example 類別有個 Reverse 方法內容為將輸入的字串反轉
  1. public class Example
  2. {
  3. public string Reverse(string input)
  4. {
  5. char[] charArray = input.ToCharArray();
  6. Array.Reverse(charArray);
  7. return new string(charArray);
  8. }
  9. }
為了驗證該方法是否正確,因此準備多種情境的參數來進行單元測試,預計測試資料如下
  • input : abc | output : cba
  • input : marcus output : sucram
  • input : apple output : elppa
撰寫多個 Method 
如果沒有使用參數化進行測試時,預估會根據每個要驗證的內容撰寫一個 method 來對應,為了在 Test Explorer 在眾多 Test cases 好識別,建議定義命名規則 ReverseTest_Input_輸入參數_Return_回傳參數,sample code 如下
  1. using NUnit.Framework;
  2.  
  3. namespace ConsoleApp2.Tests
  4. {
  5. [TestFixture()]
  6. public class ExampleTests
  7. {
  8. [Test()]
  9. public void ReverseTest_Input_abc_Return_cba()
  10. {
  11. //Arrange
  12. var ex = new Example();
  13. var input = "abc";
  14. //Act
  15. var actual = ex.Reverse(input);
  16.  
  17. //Assert
  18. Assert.AreEqual("cba", actual);
  19. }
  20. [Test()]
  21. public void ReverseTest_Input_marcus_Return_sucram()
  22. {
  23. //Arrange
  24. var ex = new Example();
  25. var input = "marcus";
  26.  
  27. //Act
  28. var actual = ex.Reverse(input);
  29.  
  30. //Assert
  31. Assert.AreEqual("sucram", actual);
  32. }
  33. [Test()]
  34. public void ReverseTest_Input_apple_Return_elppa()
  35. {
  36. //Arrange
  37. var ex = new Example();
  38. var input = "apple";
  39.  
  40. //Act
  41. var actual = ex.Reverse(input);
  42.  
  43. //Assert
  44. Assert.AreEqual("elppa", actual);
  45. }
  46. }
  47. } 
缺點會如果測試案例很多的化會有很多重複的 Code,避免重複可能會自己寫一個類別用集合跟迴圈來解決重複 Code的問題

使用 TestCase 
在 NUnit 中提供 TestCase Attribute 來透過不同數據來測試,首先改寫 ReverseTest 方法將輸入值預期結果當作參數,接著在要測試的方法上掛 TestCase attribute 並定義要測試的參數資料,看起來 Code 比較乾淨沒有重複的代碼sample code 如下
  1. using NUnit.Framework;
  2.  
  3. namespace ConsoleApp2.Tests
  4. {
  5. [TestFixture()]
  6. public class ExampleCaseTests
  7. {
  8. [Test()]
  9. [TestCase("abc", "cba")]
  10. [TestCase("marcus", "sucram")]
  11. [TestCase("apple", "elppa")]
  12. public void ReverseTest(string input, string output)
  13. {
  14. var ex = new Example();
  15. var actual = ex.Reverse(input);
  16. Assert.AreEqual(input, actual);
  17. }
  18. }
  19. } 

使用 TestCaseSource 
NUnit 另外也提供 TestCaseSource 測試不同數據,在 ReverseTest 方法使用 TestCaseSource 定義要測試的集合名稱 TestDataCases,另外在 TestDataCases 定義要測試的數據內容集合sample code 如下

  1. using NUnit.Framework;
  2. using System.Collections;
  3.  
  4. namespace ConsoleApp2.Tests
  5. {
  6. [TestFixture()]
  7. public class ExampleCaseDataTests
  8. {
  9. [Test, TestCaseSource("TestDataCases")]
  10. public void ReverseTest(string input, string output)
  11. {
  12. var ex = new Example();
  13. var actual = ex.Reverse(input);
  14. Assert.AreEqual(output, actual);
  15. }
  16.  
  17. public static IEnumerable TestDataCases
  18. {
  19. get
  20. {
  21. yield return new TestCaseData("abc","cba");
  22. yield return new TestCaseData("marcus","sucram");
  23. yield return new TestCaseData("apple","elppa");
  24. }
  25. }
  26. }
  27. } 
TestCaseData 提供 returns 方法,如果要測試的方法是有回傳值時可以在 return 方法加上參數來驗證回傳值是否正確

Test Explore 可讀性
三種方式都可以解決問題(第一種有點來亂的?),但可讀性也是蠻重要的一個環節,可以比對三者在 Test Explore 呈現的結果,以這 sample code 簡單的測試案例來說 TestCase 與 TestCaseSource 可讀性來看是較好的,測試代碼上亦是如此,但如果在較為複雜的測試案例上或許有不同結果,各位可以在實作時自己斟酌使用適合的方式

參考
NUnit
Test Generator NUnit extension
TestCase Attribute



Related Posts:

  • [.NET] QueryString 的那些事 概述 Querystring(查詢字串)是附加在網頁URL結尾的資訊。主要是在Url上傳遞資料,可能是一個搜尋字串、頁碼、某項特定的指標…或類似的東西 在網址結尾加上一個問號(?)開始,每一組參數都是用「&」區隔開來,是一種KEY / Value的組合。 舉例來說(參考上圖),在Yahoo首頁搜尋引擎輸入「Hello world」後,在按下搜尋按鈕,會導頁到查詢結果頁面,並將符合搜尋字串相關資料呈現出來。 運作原理是透過Querystrin… Read More
  • [.NET] ASP.NET 狀態管理(State Management):ViewState Web應用程式是沒有狀態(Stateless)的,從前面介紹的文章(Application、Page Life-Cycle)可以了解到,每次用戶端發送請求(Request)到伺服器端時,都會建立Web網頁類別的新執行個體。由於每個請求都是新的個體,這也代表每次來回存取時,網頁及控制項的資訊將會遺失。例如,根據預設,當使用者在網頁textbox控制項輸入「Hello world」,按下按鈕送出後,這項資訊就會傳送到伺服器。但伺服器在回傳(Res… Read More
  • [.NET] 字串加密 MD5、SHA1 常在開發中遇到需要將特定資料加密的動作,在儲存到資料庫中(比如說網站用戶的密碼加密後存到資料庫中,用戶在登入時,在把用戶輸入的密碼進行加密,再與資料庫密碼欄位比較是否一致)在.NET Framework中,可以透過 System.Security.Cryptography 命名空間來產生加密演算法的金鑰(註一),在用雜湊值(Hash Value)的加密方式達到目的,雜湊演算法將任意長度的二進位值對應到固定長度較小的二進位值,稱為雜湊值 (Ha… Read More
  • [C#] Named Arguments 具名引數前言  同事在開發專案時詢問某 method 有多個參數,有些參數是選擇輸入有預設值,因參數太多是否有方法可以指定參數名字 ? 否則一堆有設定預設值的在閱讀代碼會造成困擾,不小心也可能傳入錯誤變數,聽到當下建議抽成一個 Model 這樣更容易維護,但他表示由於引用的方法過多會擔心會牽一髮動全身,會有不可預期和毀滅性的災害發生,因此可以使用 具名引數 named arguments 來指定需要傳入的… Read More
  • [.NET] Default 和 NativeImage 資料夾問題 收到同事反應公司 Server C:\ 硬碟空間嚴重不足,確認後發現 C:\errors 資料空間占了 25g 而且還以驚人的速度成長中,進到資料夾底下查看分 Default 與 NativeImage folder 存放各種應用程式 Log ,如下圖所示 其中竟然還有 w3wp.exe,到底這些是如何記錄的呢 ? 本篇文章簡單記錄解決問題的過程 解決方案 為了追根究柢,點開其中 w3wp.exe 資料… Read More

1 則留言:

  1. 第一章圖使用 TestCase 的截圖裡面code寫錯了,是Assert.AreEqual(output, actual);才對,我看後面的截圖有修正

    回覆刪除

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

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com