Microsoft Fakes 可以提供成員模擬的方法.以方便進行單元測試
如果不使用模擬方法我們要關心很多東西,如數據庫的數據變化,接口調用導致的變化,文件、及其它資源的訪問等問題。
使用模擬我們則可以只關系我們需要測試的那部分邏輯。
一 、Stub 和 Shim
Microsoft Fakes 提供了兩種模擬類型成員的方式.以下兩種方式的替代實現,都可以由委托來重新實現.
1.Stub Type,存根類型,可以動態地為接口及非密封的virtual或屬性附加委托,以重新定義其實現,生成的類為強類型.
2.Shim Types,填充類型,解決了密封類或static成員的問題,T的填充類型ShimT可以為T的每個成員提供一個替代實現
二 、選擇原則
由於Stub和Shim的實現方式不同,所以它們也有不同的要求,下面總結了選擇它們的一些原則:
性能方面:運行時使用Shim重寫會影響性能,Stub由於使用的是虛方法,則無此問題
對static方法/sealed類型:Stub類型只可以重寫虛方法,因此,它不適用於static方法/sealed方法/sealed類中的方法,等
Internal類型:對於標記了InternalsVisibleToAttribute的內部類型,Fakes也可以起作用
private方法:如果private方法的簽名上的所有類型都是可見類型,那么可以通過Shim來替換實現.Stub只能替換可見方法.
接口和抽象方法:Stub可以提供接口或抽象方法的替代實現.Shim則不能,因為沒有實際的方法體.
所以建議在一般情況下使用Stub來支持那些可測試性做的非常好的類型,而用Shim來解決那些耦合很大,可測試性很差的代碼或三方組件.
三、如何使用Fakes
假設我們在項目ClassLibrary1中有以下幾個類
1: public interface IDataAccess
2: {
3: int Read();
4: }
5:
6: public class MyDataAccess : IDataAccess
7: {
8: public int Read()
9: {
10: return Tools.GetNum();
11: }
12: }
13:
14: public class Tools
15: {
16: static public int GetNum()
17: {
18: return 1;
19: }
20: }
21:
22: public class MyClass
23: {
24: public static int GetMyData(IDataAccess obj)
25: {
26: //其它邏輯
27: return obj.Read();
28: }
29: }
我們要使用Fakes進行測試只需要在測試項目中引用 ClassLibrary1,並且在之上右鍵->建立 Fakes即可使用Fakes
之后我們就可以使用類似以下代碼來模擬一個IDataAccess的實例 ,MyClass.GetMyData 這個static方法的實現
前者即使用Stub,后者即Shim
1: [TestClass]
2: public class UnitTest1
3: {
4: [TestMethod]
5: public void StubTest()
6: {
7: IDataAccess stockFeed = new ClassLibrary1.Fakes.StubIDataAccess()
8: {
9: Read = () => { return 2; }
10: };
11: Assert.AreEqual(2, MyClass.GetMyData(stockFeed));
12:
13: }
14: [TestMethod]
15: public void ShimTest()
16: {
17: using (ShimsContext.Create())
18: {
19: ClassLibrary1.Fakes.ShimMyClass.GetMyDataIDataAccess = (inc) => { return 2; };
20: Assert.AreEqual(2, MyClass.GetMyData(null));
21: }
22:
23: }
24:
25: }
Stub 與其它Mock差不多,只是使用委托來改變方法實現
而Shim則需要建立 ShimsContext的作用域
注意:暫時發現Shim測試在Resharper UnitTest Session運行異常,使用VS則無問題