這個系列,請見
單元測試(1): 什麼是單元測試
單元測試(2): 單元測試的好與壞
另一種常見不好的單元測試,是測試與時間相關的程式。
舉例來說,有個 IsTimeMath() 的 method,要傳回當天的時間是否已過了當年的四分之三。程式大概如下:
public class Class1 { public bool IsMatch() { DateTime today = DateTime.Today; DateTime lastDayInYear = new DateTime(today.Year, 12, 31); return ((float)today.DayOfYear) / lastDayInYear.DayOfYear > 0.75f; } }不好的測試程式如下
//////A test for IsMatch /// [TestMethod()] public void IsMatchTest() { Class1 target = new Class1(); bool expected = false; bool actual = target.IsMatch(); Assert.AreEqual(expected, actual); }
當在寫測試程式時,您會發現測試邏輯是想不出來的。原因呢?沒有任何參數需要輸入,卻需要聲明測試是否正確?很怪吧!
既然測試邏輯想不出來,代表原來的需求是錯的嗎?也不是,因為需求的確是「回傳當天的時間是否已過了當年的四分之三」。
那到底是怎麼樣?不是需求的問題,測試也寫不出來,到底該怎麼辦?
原來,追究原因,是 IsMatch 這個方法是難以測試的 (not testable),原因是與時間相關,而時間一直變動。
解決的方法,是讓 method 改成與時間無關,才是可測試的 method。改 IsMatch() 如下
public class Class1 { public bool IsMatch() { return IsMatch(DateTime.Today); } public virtual bool IsMatch(DateTime today) { DateTime lastDayInYear = new DateTime(today.Year, 12, 31); return ((float)today.DayOfYear) / lastDayInYear.DayOfYear > 0.75f; } }
我做了什麼改變呢?我將程式改寫為兩個。第一個 IsMatch() 呼叫 第二個 IsMatch(DateTime today)。主要的邏輯放在第二個 IsMatch(DateTime today)
改變的動機,是
1. 第二個 IsMatch(DateTime today) 才具可測試性,才寫得出測試邏輯來
2. 第一個 IsMatch() 符合原需求。
這樣一來,IsMatch(DateTime currentDate) 才是可測試的,Unit test 才寫的出,而且也符合需求。
沒有留言:
張貼留言