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:
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; }
{ 1 } Trackback
[...] to web applications which I don’t need for the unit test. So I use the Moq framework and a mocked context which I posted earlier. In general, to create a mock of a certain type using Moq, you [...]
Post a Comment