【Unit Test】使用Stub破除依賴(一)
/
0 Comments
打破依賴的重構方法分為兩類,我們分別稱為A型和B型重構,兩者相互依賴:
A: 把具體的類別抽象成接口(interfaces)或是委派(delegates)。
- 抽取出一個接口,使底層實現可以替換
B: 重構代碼,藉由重構來產生能注入這種委派和接口的偽實現(fake implementation)。
- 在被測試類別中注入一個Stub實體
- 在建構子注入一個偽對象
- 注入一個作為屬性設置和讀取的偽對象
- 在一個方法呼叫前,注入一個偽對象
先來介紹 "抽取出一個接口,使底層實現可以替換" :
簡單來說,就是將方法從類別中提取成介面。
舉個例,想測試MemberService的GetMemberID方法,先將這個方法用到的外部資源MemberRepository隔離開來,抽成介面IMemberRepository,接著就可以用這個介面當接口
程式碼如下:
返回固定值的簡單Stub程式碼如下:
A: 把具體的類別抽象成接口(interfaces)或是委派(delegates)。
- 抽取出一個接口,使底層實現可以替換
B: 重構代碼,藉由重構來產生能注入這種委派和接口的偽實現(fake implementation)。
- 在被測試類別中注入一個Stub實體
- 在建構子注入一個偽對象
- 注入一個作為屬性設置和讀取的偽對象
- 在一個方法呼叫前,注入一個偽對象
先來介紹 "抽取出一個接口,使底層實現可以替換" :
簡單來說,就是將方法從類別中提取成介面。
舉個例,想測試MemberService的GetMemberID方法,先將這個方法用到的外部資源MemberRepository隔離開來,抽成介面IMemberRepository,接著就可以用這個介面當接口
程式碼如下:
//抽取前 public class MemberRepository { public string GetID(string name) { .... } } public class MemberService { public string GetMemberID(string name) { MemberRepository memberrepository = new MemberRepository(); return memberrepository.GetID(name); } } //抽取後 public class MemberRepository : IMemberRepository { public string GetID(string name) { .... } } public class MemberService { //被測試的方法 public string GetMemberID(string name) { IMemberRepository imr = new MemberRepository(); return imr.GetID(name); } } interface IMemberRepository { string GetID(string name); }
返回固定值的簡單Stub程式碼如下:
//Stub public class FakeMemberRepository : IMemberRepository { public string GetID(string name) { return "123"; } } //引用Stub public string GetMemberID(string name) { IMemberRepository imr = new FakeMemberRepository(); return imr.GetID(name); }