外部依賴對象
對于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;
工作流程圖如下
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5yN6dGcxYzMxMTNxcDMyADNxAjMfJzN2IDO5QTMvwlMw8CX0EDMy8CXzRnbl1GajFGd0F2Lc12bj5yZulGdzVGdxUjL3d3dvw1LcpDc0RHaiojIsJye.jpg)
最後我們來看看我們的測試代碼,
我們把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("[email protected]", mockemailsender.to);
assert.areequal("[email protected]", mockemailsender.from);
assert.areequal("webserive log error", mockemailsender.subject);
stub和mock的相同處
從上面的例子我們可以看出, stub和mock都是模拟外部依賴,以便我們能控制。
stub 和mock 的差別
stub是完全模拟一個外部依賴, 而mock用來判斷測試通過還是失敗
良好的産品代碼才能單元測試
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5yN6dGcxYzMxMTNxcDMyADNxAjMfJzN2IDO5QTMvwlMw8CX0EDMy8CXzRnbl1GajFGd0F2Lc12bj5yZulGdzVGdxUjL3d3dvw1LcpDc0RHaiojIsJye.jpg)
如果産品代碼是下面那樣,你就沒辦法測試了。 因為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("[email protected]", "[email protected]", "webserive log error", e.message);
mock架構
其實我們沒有必要自己寫mockemailservice方法。 已經有現成的mock架構可以用了, .net中有rhino mock 和 moq, 這兩個架構比較好用
最新内容請見作者的github頁:http://qaseven.github.io/