How do I mock a page request for a .net MVC page?
3 Answers
Using RhinoMocks:
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
httpContext.Expect( c => c.Request ).Return( httpRequest ).Repeat.Any();
... set up expectations on request...
var controller = new MyController();
controller.ControllerContext = new ControllerContext( httpContext,
new RouteData(),
controller );
...invoke action, check assertions...
httpContext.VerifyAllExpectations();
httpRequest.VerifyAllExpectations();
Comments
Using Moq:
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
request.Setup(x => x.ApplicationPath).Returns("/");
request.Setup(x => x.Url).Returns(new Uri("http://localhost/home"));
request.Setup(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new YourController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
Comments
Manually (because I hate Mocking frameworks that require 8 lines of setup per test)
// in some common location, only once
public class MockHttpContext : HttpContextBase
{
public MockHttpRequest m_request = new MockHttpRequest();
public MockHttpResponse m_response = new MockHttpResponse();
public override HttpRequestBase Request
{ get { return m_request; } }
public override HttpResponseBase Response
{ get { return m_response; } }
}
public class MockHttpRequest : HttpRequestBase
{
// override whatever bits you want (eg cookies)
}
public class MockHttpResponse : HttpResponseBase
{
// override whatever bits you want (eg cookies)
}
// in your specific test
controller = new YourController {
ControllerContext = new ControllerContext { HttpContext = new MockHttpContext() }
};
4 Comments
Arman Bimatov
I like this. This is much easier to understand than mocking. Any reason why the m_request and m_response are public?
Orion Edwards
because it's a fake object designed to make testing things easier. Making those private would just mean if I wanted to change them (and sometimes you might) I'd have to have a property, etc, etc. Some rules such as implementation hiding are actively harmful in this kind of environment
Arman Bimatov
I realized why they're public right after I asked the question. Neither Request nor Response don't have setters, because that's how it is in the HttpContextBase. So if I need to mutate the request and response from my unit tests, I need them public.
Mohoch
@OrionEdwards, this is the only answer I could find that explained how to do this simple think without mocking frameworks. It had to be built in to ASP.NET MVC, as unit tests are one of the main advantages this framework brings with it. And it is so easy. It's just a shame almost no one talks about it. Thanks a lot!!