Thursday, October 6, 2011

Mocking a web context for .Net MVC using Moq

To effectively unit test MVC Controllers you'll need to supply a web context or an HttpContext object. This is a quick and dirty way to mock out a web context that can access the Request, Response, Form, and Cookies objects. They essentially become Dictionary objects for which you can stuff values in the same way normally would for a Dictionary. Those values will be there when you run your unit tests.
public class ContextMocks {
 public Moq.Mock<HttpContextBase> HttpContext { get; private set; }
 public Moq.Mock<HttpRequestBase> Request { get; private set; }
 public Moq.Mock<HttpResponseBase> Response { get; private set; }
 public RouteData RouteData { get; private set; }

 public ContextMocks(Controller onController) {
  // Define all the common context objects, plus relationships between them
  HttpContext = new Moq.Mock<HttpContextBase>();
  Request = new Moq.Mock<HttpRequestBase>();
  Response = new Moq.Mock<HttpResponseBase>();
  
  HttpContext.Setup(x => x.Request).Returns(Request.Object);
  HttpContext.Setup(x => x.Response).Returns(Response.Object);
  HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
  Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
  Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
  Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
  Request.Setup(x => x.Form).Returns(new NameValueCollection());
  
  // Apply the mock context to the supplied controller instance
  RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
  onController.ControllerContext = new ControllerContext(rc, onController);
 }
 
 // Use a fake HttpSessionStateBase, because it's hard to mock it with Moq
 private class FakeSessionState : HttpSessionStateBase {
  Dictionary<string, object> items = new Dictionary<string, object>();
  public override object this[string name] {
   get { return items.ContainsKey(name) ? items[name] : null; }
   set { items[name] = value; }
  }
 }
}

No comments:

Post a Comment