今天要來看看單元測試的初始化設定與清除

圖片出處:https://www.codeproject.com/Articles/1165536/Unit-Test-Initialization-and-Cleanup
上圖是單元測試在執行時的生命週期,知道了這特性的時候我們就可以依據測試的需要來加入適當的初始化設定。
**
**以下範例來說明執行順序
這邊準備了一個Static Class,裡面有個Get方法很簡單的回傳Now這個屬性值
1 2 3 4 5 6 7 8 9 10
| public static class Demo { public static int Now { get; set; }
public static int Get() { return Now; } }
|
然後為它建立單元測試

先加上一個TestHook的檔案

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| [TestClass] public class TestHook { [AssemblyInitialize] public static void AssemblyInit(TestContext context) { Console.WriteLine(string.Format("{0} - AssemblyInitialize", Demo.Get())); Demo.Now += 1; }
[AssemblyCleanup] public static void AssemblyCleanUp() { Console.WriteLine(string.Format("{0} - AssemblyCleanup", Demo.Get())); Demo.Now += 1; } }
|
接著撰寫DemoTests.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| [TestClass] public class DemoTests { [ClassInitialize] public static void ClassInit(TestContext context) { Console.WriteLine(string.Format("{0} - ClassInitialize", Demo.Get())); Demo.Now += 1; }
[TestInitialize] public void TestInit() { Console.WriteLine(string.Format("{0} - TestInitialize", Demo.Get())); Demo.Now += 1; }
[TestMethod] public void GetTest() { Console.WriteLine(string.Format("{0} - Test1", Demo.Get())); Demo.Now += 1; }
[TestCleanup] public void TestCleanUp() { Console.WriteLine(string.Format("{0} - TestCleanup", Demo.Get())); Demo.Now += 1; }
[ClassCleanup] public static void ClassCleanUp() { Console.WriteLine(string.Format("{0} - ClassCleanup", Demo.Get())); Demo.Now += 1; } }
|
這裡目標很間單,測試的內容不是重點,而是希望透過輸出來看到執行的順序
可能有人會注意到為何有些方法例如ClassCleanup是需要Static,有些又需要帶入TestContext的參數?
這其實是規定,如果不按照規則撰寫的話,執行單元測試時就會得到以下錯誤訊息

接著執行單元測試看看輸出,點擊下面的輸出按鈕


這樣看就很明顯知道順序了!!
讓我們加上第二個測試
1 2 3 4 5 6 7
| [TestMethod] public void GetTest2() { Console.WriteLine(string.Format("{0} - Test2", Demo.Get())); Demo.Now += 1; }
|
全部測試執行然後看看結果



可以發現TestInitialize與TestCleanUp是每個測試在執行前/後都會執行一次的,而且要特別強調一下,每個單元測試執行的順序是不固定的,所以如果在單元測試中有些初始化的動作,切記不要依賴每個測試之間的順序關係,否則可能會不定時的產生錯誤,請把每個測試都當成是獨立且無相依關係!!
從這個範例也可以看得到一個結論,如果在測試中有用到Production Code中Static的參數或屬性,請記得養成良好習慣,要在CleanUp的方法中恢復它的預設值,否則Static是共用的,如果其他測試有用到同一個Static屬性,而互相改來改去不初始化,就很可能發生單元測試時好時壞的問題,這是切身之痛請勿以身試法XDD