【Unit Test】Stub破除依賴(四) - 抽取和重寫範例一

/
0 Comments

前言:

相信很多人都遇過Legancy Code,改沒有留下測試的Legancy Code最怕的就是改了東卻壞了西卻還不知道,為了避免類似問題,我們可以嘗試在Legancy Code中加入單元測試。但是事情往往沒那麼順利,很多專案都外部依賴的很頻繁,想重構切出介面等可能工程浩大,要想在動到最少程式碼的情況下去加入單元測試,"抽取和重寫(extract and override)"會是個有用的技術。


使用被測試類別中的一個virtual方法做為工廠方法,在MemberService的子類別複寫這個虛擬方法,產生出你需要的接口。在接口注入你準備好的Stub物件,之後測試就以子類別來進行。
程式碼如下:

//原程式碼
public class MemberRepository
{
 public string GetID(string name)
 {
  return "Original";
 }
}

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)
 {
  return "Original";
 }
}

public interface IMemberRepository
{
 string GetID(string name);
}

public class MemberService
{
 protected virtual IMemberRepository GetRepository()
 {
  return new MemberRepository();
 }

 //被測試的方法
 public string GetMemberID(string name)
 {
  return GetRepository().GetID(name);
 }
}

public class TestableMemberService : MemberService
{
 private IMemberRepository _IMemberRepository;

 public TestableMemberService(IMemberRepository memberRepository)
 {
  this._IMemberRepository = memberRepository;
 }

 protected override IMemberRepository GetRepository()
 {
  return this._IMemberRepository;
 }
}


測試程式碼 :
//Stub
public class FakeMemberRepository : IMemberRepository
{
 public string returnID { get; set; }
 public string GetID(string name)
 {
  return returnID;
 }
}

[TestMethod()]
public void GetMemberID_Test()
{
 //arrange
 var name = "Tom";
 var expected = "321";

 var stub = new FakeMemberRepository();
 stub.returnID = expected;
 TestableMemberService sut = new TestableMemberService(stub);


 //act
 var actual = sut.GetMemberID(name);

 //assert
 Assert.AreEqual(expected, actual);
}

結語:

抽取和重寫建立了全新的間接層,接近被測試單元的表層,越接近表層表示你需要修改的依賴項目就越少。抽取和重寫很適合用在模擬提供給被測試單元的輸入,例如呼叫其他方法取得值然後繼續做後續的操作。


You may also like

沒有留言: