首页 > 代码库 > Mock 和 Stub 的异同
Mock 和 Stub 的异同
Mock 和 Stub 都属于单元测试的范畴,他们有共同点,同时也有不同点。
那就拿我的一个例子去说明,先上一段代码:
public abstract class HttpContextBase
{
protected HttpRequestBase request = null;
protected HttpResponseBase response = null;
public virtual HttpRequestBase Request
{
get
{
return request;
}
set
{
request = value;
}
}
public virtual HttpResponseBase Response
{
get
{
return response;
}
set
{
response = value;
}
}
}
public abstract class HttpRequestBase
{
protected NameValueCollection urlParams = null;
public virtual NameValueCollection Params
{
get
{
return urlParams;
}
set
{
urlParams = value;
}
}
}
public abstract class HttpResponseBase
{
protected string responseMsg = null;
protected string contentType = null;
public virtual string ResponseMsg
{
get
{
return responseMsg;
}
}
public virtual string ContentType
{
get
{
return contentType;
}
set
{
contentType = value;
}
}
public virtual void Write(string message)
{
responseMsg = message;
}
}
本测试主要测试 GetExamHandler 中的ProcessRequest 方法,在其中调用了IExamService的接口方法 GetExams(),然后将结果以application/json的格式返回给客户端。
由于HttpHandler中对于HttpContext不好模拟,因此我自己又封装了一层,并使他们都继承了基类如:HttpContextBase,HttpRequestBase和HttpResponseBase。
[TestMethod] public void ProcessRequestTest_Mock() { string strExpected = "Tested String"; GetExamHandler target = new GetExamHandler(); var mockContext = new Mock<Models.HttpContextBase>(); var mockRequest = new Mock<Models.HttpRequestBase>(); var mockResponse = new Mock<Models.HttpResponseBase>(); var objContext = mockContext.Object; var objRequest = mockRequest.Object; var objResponse = mockResponse.Object; mockContext.Setup(o => o.Request).Returns(objRequest); mockContext.Setup(o => o.Response).Returns(objResponse); NameValueCollection urlParams=new NameValueCollection(); urlParams.Add("n", "true"); urlParams.Add("secKey", "IsuibianxieDT"); mockRequest.Setup(o => o.Params).Returns(urlParams); mockResponse.Setup(o => o.ContentType).Returns("application/json"); var mockExamService=new Mock<IExamService>(); mockExamService.Setup(p => p.GetExams()).Returns(strExpected); string strActual = string.Empty; mockResponse.Setup(p => p.Write(strExpected)).Callback<string>(str => strActual = str); target.ProcessRequest(objContext); Assert.AreEqual(strExpected, strActual); }
上面这段代码,利用Mock的方式来模拟HttpContextBase。
public class FakeHttpContext : Models.HttpContextBase{}public class FakeRequest : Models.HttpRequestBase{}public class FakeResponse : Models.HttpResponseBase{}[TestMethod]public void ProcessRequestTest_Stub(){
string strExpected = "Tested String";GetExamHandler target = new GetExamHandler(); var objContext = new FakeHttpContext();var objRequest = new FakeRequest();var objResponse = new FakeRequest();objContext.Request=objRequest;objContext.Response=objResponse; NameValueCollection urlParams=new NameValueCollection();urlParams.Add("n", "true");urlParams.Add("secKey", "IsuibianxieDT");objRequest.Params=urlParams;var mockExamService=new Mock<IExamService>();mockExamService.Setup(p => p.GetExams()).Returns(strExpected);string strActual = string.Empty;target.ProcessRequest(objContext);Assert.AreEqual(strExpected, objResponse.ResponseMsg);
}
上面的代码,利用Stub的方式来模拟HttpContextBase,可以看出创建了几个Fake类:FakeHttpContext,FakeRequest和FakeResponse。
根据以上代码,我们总结下二者的相同点:
1.在被测试方法中,都存在对象依赖关系。
2.都是利用多态的方式,通过Test Double 将真正的实现逻辑隔离出来。
3.二者都可以用来进行方法的单元测试。
再来说说二者的不同点:
1.虽然二者都可以进行单元测试,但是对于Stub方法,需要在测试时实现一些Fake的对象逻辑;而Mock不需要实现逻辑。因为Mock框架(如Moq)都已经帮你实现了。
2.关注点不同。Stub方法更加关注对象的状态,比如例子中objResponse.ResponseMsg;而Mock则关注对象的行为,即某个方法是否被执行,如代码中
mockResponse.Setup(p => p.Write(strExpected)).Callback<string>(str => strActual = str); 只有被测试代码中Response.Write(string)被执行时,后面的回调才会起作用。
因此MartinFowler在他的文章《Mocks Aren‘t Stubs》中说,Stub是State-Based Testing,而Mock是Interaction-Based Testing。因此二者的区别,引用MartinFowler原话就是:The difference is in how exactly the double runs and verifies.