首页 > 代码库 > 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.