在實際開發中,經常會遇到這樣的情況。
一個共有的 Public 方法實現某一主要功能,但是由於該功能的實現非常復雜,需要很多的輔助類,輔助方法。由於代碼封裝性的需求,我們通常需要把這些輔助的類方法定義為非Public,靜態static的(非必須,但是靜態方法會提升性能),如 private, internal 等。
但是這也帶來了一個問題,如何對這些非 public 的類,方法進行單元測,畢竟這些才是完成邏輯的代碼?
我作為一個開發人員,如果讓我說,有以下幾種方式:
- 修改修飾符為 public, 測試完成后再修改回去-- 但是這個破壞了 Unit Test 的意義,因為它不能再任何情況下都運行。
- 反射-- 寫反射的代碼,動態的調用相應的方法。可以但是為了一個單元測試寫這么多工具代碼會不會太浪費了。
- 使用 InternvalVisibleTo 屬性--[InternalsVisibleTo(“UnitTestProject.Assembly”)] 設置當前項目對單元測試的項目可見,所有的私有方法采用 Internal 限制,但是這個會不會破壞了封裝那?
難道微軟就沒有考慮過這個問題么?
當然,答案是 PrivateObject/PrivateType -- 實際上采用的是我的第二種方式,但是做了微軟做了很多處理哦,省得我們麻煩。
PrivateObject對應測試的是實例方法,PrivateType 對應測試的是靜態方法。
假設我們有一個 Calculate 類如下:
public class Calculate { internal static int AddStatic(int a, int b) { return a + b; } private int Add(int a, int b) { return a + b; } }
然后我們要對其進行測試
- 那么針對實例的 Add 方法測試代碼如下
[TestMethod] public void TestPrivateAdd() { PrivateObject po = new PrivateObject(new Calculate()); Assert.AreEqual(po.Invoke("Add", 1, 2), 3); }
- 測試靜態的 Internal 的 AddStatic 代碼如下:
[TestMethod] public void TestInternalStaticAdd() { PrivateType po = new PrivateType(typeof(Calculate)); Assert.AreEqual(po.InvokeStatic("AddStatic", 1, 2), 3); }