單元測試之Stub和Mock

來源:互聯網
上載者:User

在做單元測試的時候,我們會發現我們要測試的方法會引用很多外部依賴的對象,比如:(發送郵件,網路通訊,記錄Log, 檔案系統 之類的)。 而我們沒法控制這些外部依賴的對象。  為瞭解決這個問題,我們需要用到Stub和Mock來類比這些外部依賴的對象,從而控制它們

 

閱讀目錄

  1. 執行個體
  2. 設計測試案例
  3. 什麼是外部依賴
  4. Stub和Mock的相同處
  5. Stub和Mock的區別
  6. 良好的產品代碼才能單元測試
  7. Mock架構
  8. 原始碼下載

 

執行個體

Analyze類會檢查filename的長度,如果小於8,我們就會使用一個實現IWebService的類來記錄錯誤.

我們需要給Analyze方法寫單元測試。

public class LogAnalyzer
{
private IWebService service;
private IEmailService email;

public IWebService Service
{
get { return service; }
set { service = value; }
}

public IEmailService Email
{
get { return email; }
set { email = value; }
}

public void Analyze(string fileName)
{
if (fileName.Length < 8)
{
try
{
service.LogError("the file name is to short" + fileName);
}
catch (Exception e)
{
email.SendEmail("From@test.com", "To@test.com", "IWebServiceFailed", e.Message);
}
}
}
}
設計測試案例

測試案例一: 

fileName= "c:\test\test.txt" (長度大於8),      

期待測試結果: 不會發郵件

測試案例二: 

fileName="c:\",(長度小於8),  並且記log失敗 。  

期待測試結果: 發郵件

 

如果給Analyze方法寫單元測試,為了實現測試案例二。  這時候我們就會碰到兩個問題。

第一: 我們無法控制讓Service對象記log時拋出異常. 因為Serveice對象我們無法控制

第二: 我們無法判斷,Email對象是否發送了Email, (我們不能去Outlook查看收到郵件沒有,這樣就不是自動化了)

 

外部依賴對象

對於LogAnalyzer對象來說, Service和Email就是兩個外部依賴對象. 我們需要自己寫Stub和Mock來類比這兩個外部依賴對象。這樣我們才能控制他們。

 

我們在測試的代碼中建立StubWebService和MockEmailService.這兩個class分別實現了IWebService和IEmailService. 

 

public class StubWebService : IWebService
{
public void LogError(string message)
{
throw new Exception("StubWebService throw exception");
}
}

public class MockEmailService : IEmailService
{
public string To;
public string From;
public string Subject;
public string Message;

public void SendEmail(string to, string from, string subject, string message)
{
To = to;
From = from;
Subject = subject;
Message = message;
}
}

 

工作流程圖如下

 

最後我們來看看我們的測試代碼,

我們把StubWebService和MockEmailService兩個類的執行個體注入到產品代碼中。(因為多態特性嘛)。

通過控制StubWebService中的LogError方法,拋出一個異常。

然後判斷MockEmailService中的SendEmail方法有沒有被調用. 被調用了說明發送了Email(我們不需要真的收到一封郵件,因為SendEmail功能是IEmailService實現的,)

 

[TestMethod]
public void TestMethod1()
{
StubWebService stubWebService = new StubWebService();
MockEmailService mockEmailSender = new MockEmailService();

LogAnalyzer log = new LogAnalyzer();
log.Emailservice = mockEmailSender;
log.WebService = stubWebService;

// Act
string tooShortFileName = "1.txt";
log.Analyze(tooShortFileName);

// Assert
Assert.AreEqual("to@test.com", mockEmailSender.To);
Assert.AreEqual("from@test.com", mockEmailSender.From);
Assert.AreEqual("WebSerive log error", mockEmailSender.Subject);
}

 

Stub和Mock的相同處

從上面的例子我們可以看出, Stub和Mock都是類比外部依賴,以便我們能控制。

 

Stub 和Mock 的區別

Stub是完全類比一個外部依賴, 而Mock用來判斷測試通過還是失敗

 

 

良好的產品代碼才能單元測試

如果產品代碼是下面那樣,你就沒辦法測試了。 因為WebService和EmailService兩個類沒有繼承介面。我們無法把StubWebService和MockEmailService兩個類注入到產品代碼。

 

    public class LogAnalyzer
{
private WebService webService;
private EmailService emailService;

public WebService WebService
{
get { return webService; }
set { webService = value; }
}

public EmailService Emailservice
{
get { return emailService; }
set { emailService = value; }
}

public void Analyze(string fileName)
{
if (fileName.Length < 8)
{
try
{
WebService.LogError("Filename too short:" + fileName);
}
catch (Exception e)
{
Emailservice.SendEmail("to@test.com", "from@test.com", "WebSerive log error", e.Message);
}
}
}
}

 

Mock架構

其實我們沒有必要自己寫MockEmailService方法。  已經有現成的Mock架構可以用了, .NET中有Rhino Mock 和 Moq,  這兩個架構比較好用

 

原始碼下載

 

點擊此處下載完整的原始碼, 請用VS2008開啟

 

[參考] The Art of Unit Testing

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.