public
Last active

MvcMockHelpers.cs - Helper Utility for Mocking MVC3 Controllers with Moq.

  • Download Gist
MvcMockHelpers.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
 
/// <summary>
/// This helper class can be used to set up Moq mocks of MVC3 controllers.
/// Slightly modified from the original version from Scott Hanselman's blog:
/// http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx
/// </summary>
public static class MvcMockHelpers
{
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>();
 
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.SetupProperty(ctx => ctx.User);
 
return context.Object;
}
 
public static HttpContextBase FakeHttpContext(string url)
{
var context = FakeHttpContext();
context.Request.SetupRequestUrl(url);
return context;
}
 
public static void SetFakeControllerContext(this Controller controller, string requestUrl = "~/Nowhere/")
{
var httpContext = FakeHttpContext(requestUrl);
var requestContext = new RequestContext(httpContext, new RouteData());
var context = new ControllerContext(requestContext, controller);
controller.ControllerContext = context;
controller.Url = new UrlHelper(requestContext);
}
 
private static string GetUrlFileName(string url)
{
return url.Contains("?") ? url.Substring(0, url.IndexOf("?")) : url;
}
 
private static NameValueCollection GetQueryStringParameters(string url)
{
if (url.Contains("?"))
{
var parameters = new NameValueCollection();
 
var parts = url.Split("?".ToCharArray());
var keys = parts[1].Split("&".ToCharArray());
 
foreach (var key in keys)
{
var part = key.Split("=".ToCharArray());
parameters.Add(part[0], part[1]);
}
 
return parameters;
}
return null;
}
 
public static void SetHttpMethodResult(this HttpRequestBase request, string httpMethod)
{
Mock.Get(request)
.Setup(req => req.HttpMethod)
.Returns(httpMethod);
}
 
public static void SetupRequestUrl(this HttpRequestBase request, string url)
{
if (url == null)
throw new ArgumentNullException("url");
 
if (!url.StartsWith("~/"))
throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\".");
 
var mock = Mock.Get(request);
 
mock.Setup(req => req.QueryString)
.Returns(GetQueryStringParameters(url));
mock.Setup(req => req.AppRelativeCurrentExecutionFilePath)
.Returns(GetUrlFileName(url));
mock.Setup(req => req.PathInfo)
.Returns(string.Empty);
mock.SetupGet(x => x.Url).Returns(new Uri(url.Replace("~/", "http://www.nowhere.com/")));
}
}

Sample Usage:

var controller = new SomeController();
controller.SetFakeControllerContext("~/Somewhere/");

This will set up the HttpContext, RequestContext, and UrlHelper inside the controller, so that the controller code can still execute.

Also allows the user Principal to be set on the HttpContext:

var controller = new SomeController();
controller.SetFakeControllerContext();
controller.HttpContext.User = new GenericPrincipal(new GenericIdentity("username"), new string[0]);

I'm new at this... How do I integrate this into the Controller? Are you adding that static method to the controller?

Added a modified version of this that creates/returns a dictionary of all mocked objects in a controller
Gist can be found here
https://gist.github.com/3955791

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.