Here's my solution for this in MVC5 using POCO mocking instead of a library like Moq.
HttpContext.Current = MockHttpContext.FakeHttpContext(true, "someuser@somewhere.com", true, "http://somesite.com/Path/To");
var httpContextBase = new HttpContextWrapper(HttpContext.Current);
InternalController controller = new InternalController();
RouteData route_data = new RouteData();
ControllerContext controller_context = new ControllerContext(httpContextBase, route_data, controller);
controller.ControllerContext = controller_context;
The above sets up the MVC controller, and then I test a View call like so:
var result = controller.SomeMethod(somevar) as ViewResult;
And then assert on the result any model bits it contains.
My FakeHttpContext.cs
class:
public static HttpContext FakeHttpContext(bool login = true, string user = "someuser@somewhere.com", bool add_role = true, string url = "http://tempuri.org/")
{
if(add_role)
{
MockRoleProvider mock = Roles.Provider as MockRoleProvider;
if (mock == null) throw new NullReferenceException("MockRoleProvider null exception.");
mock.ClearAll();
mock.CreateUser(user);
mock.CreateRole("User");
mock.AddUsersToRoles(new string[] { user }, new string[] { "User" });
}
var httpRequest = new HttpRequest("", url, "");
var stringWriter = new StringWriter();
var httpResponse = new HttpResponse(stringWriter);
var httpContext = new HttpContext(httpRequest, httpResponse);
var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
new HttpStaticObjectsCollection(), 10, true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc, false);
httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer });
if(login)
{
// User is logged in
httpContext.User = new GenericPrincipal(
new GenericIdentity(user),
new string[0]
);
httpContext.Session["UserID"] = user;
}
else
{
// User is logged out
httpContext.User = new GenericPrincipal(
new GenericIdentity(String.Empty),
new string[0]
);
}
return httpContext;
}
For completeness, here's my MockRoleProvider.cs
:
public class MockRoleProvider : RoleProvider
{
public MockRoleProvider()
: base()
{
Users = new List<User>();
Roles = new List<Role>();
}
#region RoleProvider members
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
if (usernames == null) throw new ArgumentNullException("usernames");
if (roleNames == null) throw new ArgumentNullException("roleNames");
foreach (string role in roleNames)
{
if (!RoleExists(role)) throw new ProviderException("Role name does not exist.");
}
foreach (string user in usernames)
{
if (Users.FirstOrDefault(u => u.Username == user) == null) throw new ProviderException("Username does not exist.");
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (var rolename in roleNames)
{
Role role = Roles.FirstOrDefault(r => r.RoleName == rolename);
user.Roles.Add(role);
role.Users.Add(user);
}
}
}
public override string ApplicationName { get; set; }
public override void CreateRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (roleName.Contains(",")) throw new ArgumentException("Role names cannot contain commas.");
if (RoleExists(roleName)) throw new ProviderException("Role name already exists.");
Roles.Add(new Role { RoleName = roleName });
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role name does not exist.");
if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0) throw new ProviderException("Cannot delete a populated role.");
Roles.Remove(Roles.FirstOrDefault(r => r.RoleName == roleName));
return true;
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
return GetUsersInRole(roleName).Where(n => n.Contains(usernameToMatch)).ToArray();
}
public override string[] GetAllRoles()
{
return Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetRolesForUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) return new string[0];
return user.Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetUsersInRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role '" + roleName + "' does not exist.");
return role.Users.Select(u => u.Username).OrderBy(n => n).ToArray();
}
public override bool IsUserInRole(string username, string roleName)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
return role != null && role.Users.FirstOrDefault(u => u.Username == username) != null;
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
foreach (string roleName in roleNames)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (!RoleExists(roleName)) throw new ProviderException("Role name not found.");
}
foreach (string username in usernames)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
foreach (string roleName in roleNames)
{
if (!IsUserInRole(username, roleName)) throw new ProviderException("User is not in role.");
}
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (string roleName in roleNames)
{
Role role = user.Roles.FirstOrDefault(r => r.RoleName == roleName);
role.Users.Remove(user);
user.Roles.Remove(role);
}
}
}
public override bool RoleExists(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
return Roles.FirstOrDefault(r => r.RoleName == roleName) != null;
}
#endregion
public void ClearAll()
{
Users = new List<User>();
Roles = new List<Role>();
}
public void ClearRoles()
{
Roles = new List<Role>();
Users.ForEach(u => u.Roles = new List<Role>());
}
public void ClearUsers()
{
Users = new List<User>();
Roles.ForEach(r => r.Users = new List<User>());
}
public void CreateUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (UserExists(username)) throw new ProviderException("User name already exists.");
Users.Add(new User { Username = username });
}
public bool DeleteUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) throw new ProviderException("User name does not exist.");
foreach (Role role in user.Roles)
{
role.Users.Remove(user);
}
Users.Remove(user);
return true;
}
public bool UserExists(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
return Users.FirstOrDefault(u => u.Username == username) != null;
}
private List<Role> Roles { get; set; }
private List<User> Users { get; set; }
private class Role
{
public Role()
{
Users = new List<User>();
}
public string RoleName { get; set; }
public List<User> Users { get; set; }
}
private class User
{
public User()
{
Roles = new List<Role>();
}
public string Username { get; set; }
public List<Role> Roles { get; set; }
}
}
And lastly from the app.config
in my unit test project:
<system.web>
<roleManager enabled="true" defaultProvider="MockRoleProvider">
<providers>
<add name="MockRoleProvider" type="MyProject.Tests.MockRoleProvider, MyProject.Tests" />
</providers>
</roleManager>
</system.web>
I also run a mock membership class and config, and use Effort to provide EF with a fake db. In terms of an integration test environment that runs just like any other unit test, it's been perfect for my purposes.