【Unit Test】使用Stub破除依賴(一)

/
0 Comments
打破依賴的重構方法分為兩類,我們分別稱為A型和B型重構,兩者相互依賴:

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);
}

結語:

這種利用實現偽對象的技術,可能導致程式碼裡有太多這種為了測試而寫的類別,將來可能不好維護,而到現在為止,你的被測試方法還是相依於IMemberRepository的實作類別,因此需要在程式碼中加入一個接口插入存根(Stub)。


You may also like

沒有留言: