單元測試之Stub和Mock
外部依賴對象
對于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用來判斷測試通過還是失敗
良好的產品代碼才能單元測試
外部依賴對象
對于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, 這兩個框架比較好用