寫程式常常會有很多難以隔離的邏輯,這邊舉一個關於時間的例子。
.
上面的邏輯正確且簡單,唯一的缺點是不好測試。為什麼呢?
試著寫一段 Unit Test 看看,你可能會像下面這樣寫
.
這個測試這樣寫的話,只有在聖誕節當天才會 Pass.
所以困難的地方在於怎麼把變動的邏輯給隔離開來。
下面提供幾個作法,在不影響已發佈的使用下來讓程式可以測次,各有優缺點
首先都是先將 DateTime.Today; 這個邏輯提取方法 GetToday(),然後
.
透過建構子,屬性,或是新的Set的方法來改變這個 private 變數 _today.
然後在隔離出來的 GetToday() 中判斷 _today 是否有被設定過值,如果有就直接回傳 _today,如果沒有就回傳 DateTime.Today。
.
這三種方法的缺點是這些都是為了測試而新增的方法或屬性,或許會被不知情的使用者誤用。那有沒有不新加功能的辦法呢? 有的,那就是透過繼承與覆寫。
.
首先也是將DateTime.Today; 這個邏輯提取方法 GetToday()
差異是關鍵字 virtual ,這個關鍵字代表可以讓子類別覆寫。
因此在測試專案中,只要寫一個 FakeXmasChecker 繼承 XmasChecker 然後覆寫GetToday()
然後直接在覆寫的方法中回傳需要的時間即可。
如下面的方法所示
如果要你寫一個判斷是不是聖誕節的簡單程式你會怎麼寫?
public bool IsTodayXmas() { var today = DateTime.Today; if (today.Month == 12 && today.Day == 16) { return true; } else { return false; } }
.
上面的邏輯正確且簡單,唯一的缺點是不好測試。為什麼呢?
試著寫一段 Unit Test 看看,你可能會像下面這樣寫
[TestMethod] public void TodayIsXmas() { var checker = new XmasChecker(); var result = checker.IsTodayXmas(); Assert.AreEqual(true, result); }
.
這個測試這樣寫的話,只有在聖誕節當天才會 Pass.
所以困難的地方在於怎麼把變動的邏輯給隔離開來。
下面提供幾個作法,在不影響已發佈的使用下來讓程式可以測次,各有優缺點
首先都是先將 DateTime.Today; 這個邏輯提取方法 GetToday(),然後
- 透過新的建構子
- 透過新的屬性
- 透過新的方法
- 使用繼承,變更 GetToday() 的存取範圍為 Protected virtual
private DateTime? _today = null; private DateTime GetToday() { return _today ?? DateTime.Today; }
.
透過建構子,屬性,或是新的Set的方法來改變這個 private 變數 _today.
然後在隔離出來的 GetToday() 中判斷 _today 是否有被設定過值,如果有就直接回傳 _today,如果沒有就回傳 DateTime.Today。
.
這三種方法的缺點是這些都是為了測試而新增的方法或屬性,或許會被不知情的使用者誤用。那有沒有不新加功能的辦法呢? 有的,那就是透過繼承與覆寫。
.
首先也是將DateTime.Today; 這個邏輯提取方法 GetToday()
protected virtual DateTime GetToday() { return DateTime.Today; }.
差異是關鍵字 virtual ,這個關鍵字代表可以讓子類別覆寫。
因此在測試專案中,只要寫一個 FakeXmasChecker 繼承 XmasChecker 然後覆寫GetToday()
然後直接在覆寫的方法中回傳需要的時間即可。
如下面的方法所示
protected override DateTime GetToday() { return new DateTime(2017, 12, 25); }.
留言
張貼留言