Moq and MvcMockHelpers
I'm working on some unit tests for an ASP.NET MVC application I'm developing. One of the tests ensures that if I construct a URL using Html.ActionLink that the URL which is returned, when fed into the routing system, becomes a correct representation of the route data used to build the URL originally. I'll discuss this further in a future post, but today I'm going to talk about Moq. Unfortunately, this type of testing requires more mocking than you'd really prefer, despite the significant improvements in unit-testability in recent previews of the ASP.NET MVC framework.
I started with the MvcMockHelpers library released by Scott Haselman. It does quite a bit of what I need, so that saved me a lot of work. Scott's library supports three different mocking frameworks; of these, I chose Moq.
My tests hit some areas of the HttpContext which Scott's mock didn't implement, so I set out to extend it. One bit, HttpContextBase.ApplyAppPathModifier, was a bit more challenging to mock, despite the fact that the result I needed was quite simple: The mocked function should simply return its only argument. The Moq demos don't cover this case, although it is a supported feature in the 2.0 version. After a little digging around through the forums and the change logs, I figured out how to do it:
There are two parts to this. First, you specify that this mock will match a call to ApplyAppPathModifier with any string argument. That is the It.IsAny bit. Inside the Returns call is a lambda expression which specifies how to turn a string argument into a result. In this case, the expression is very simple.
So, for anyone who wants it, here is my current implementation of the FakeHttpContext() method. It returns a mocked HttpContext which is good enough for the unit testing I'm doing at the moment.
I started with the MvcMockHelpers library released by Scott Haselman. It does quite a bit of what I need, so that saved me a lot of work. Scott's library supports three different mocking frameworks; of these, I chose Moq.
My tests hit some areas of the HttpContext which Scott's mock didn't implement, so I set out to extend it. One bit, HttpContextBase.ApplyAppPathModifier, was a bit more challenging to mock, despite the fact that the result I needed was quite simple: The mocked function should simply return its only argument. The Moq demos don't cover this case, although it is a supported feature in the 2.0 version. After a little digging around through the forums and the change logs, I figured out how to do it:
response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>()))
.Returns((string virtualPath) => virtualPath);
There are two parts to this. First, you specify that this mock will match a call to ApplyAppPathModifier with any string argument. That is the It.IsAny bit. Inside the Returns call is a lambda expression which specifies how to turn a string argument into a result. In this case, the expression is very simple.
So, for anyone who wants it, here is my current implementation of the FakeHttpContext() method. It returns a mocked HttpContext which is good enough for the unit testing I'm doing at the moment.
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
request.Expect(req => req.ApplicationPath).Returns("~/");
request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
request.Expect(req => req.PathInfo).Returns(string.Empty);
response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>()))
.Returns((string virtualPath) => virtualPath);
user.Expect(usr => usr.Identity).Returns(identity.Object);
identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true);
context.Expect(ctx => ctx.Request).Returns(request.Object);
context.Expect(ctx => ctx.Response).Returns(response.Object);
context.Expect(ctx => ctx.Session).Returns(session.Object);
context.Expect(ctx => ctx.Server).Returns(server.Object);
context.Expect(ctx => ctx.User).Returns(user.Object);
return context.Object;
}

I would like to appreciate the work you've made in writing this publish. It has been an inspiration for me personally. I have passed this through to a friend. thankyou