I'm trying to mock the AccountController Login method using MOQ. I have error saying To call this method, the "Membership.Provider" property must be an instance of "ExtendedMembershipProvider". The test passes if the AccountController has constructors of IWebSecurity and IOAuthWebSecurity but if I'm about to implement services constructor parameters my test fails and shows the error I've mentioned. Can anyone help me correct my mocking implementation? I'm new to mocking, MOQ, and Unit Testing. I'm using MS Test (The test that is default when you create MVC 4 project). Please help.
Working and success test
AccountController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;
using SampleWebApp.Filters;
using SampleWebApp.Models;
namespace SampleWebApp.Controllers
{
[Authorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
private IWebSecurity WebSecurity { get; set; }
private IOAuthWebSecurity OAuthWebSecurity { get; set; }
public AccountController()
: this(new WebSecurityWrapper(), new OAuthWebSecurityWrapper())
{
}
public AccountController(IWebSecurity webSecurity, IOAuthWebSecurity oAuthWebSecurity)
{
WebSecurity = webSecurity;
OAuthWebSecurity = oAuthWebSecurity;
}
//
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
}
}
Failed test
AccountController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using WebMatrix.WebData;
//reference namespace for services
namespace SampleWebApp.Controllers
{
[SinglePlatformAuthorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
private IUserAccountService UserAccountService { get; set; }
private IUserService _userService;
private readonly IParentPortalService parentPortalService;
public AccountController(IUserService userService, IParentPortalService parentPortalService)
{
this.UserAccountService = new UserAccountService();
this._userService = userService;
this.parentPortalService = parentPortalService;
}
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
Session.Clear();
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl = "")
{
returnUrl = returnUrl == "" ? Url.Action("Index", "Home") : HttpUtility.UrlDecode(returnUrl);
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, model.RememberMe))
{
SessionVariables sessionVariables;
// Set static accountid for now
var authenticatedModel = this.UserAccountService.GetUserAuthenticatedModel(model.UserName);
....
return Json(new { success = true, url = returnUrl });
}
}
}
}
Unit Test Code/files
IOAuthWebSecurity.cs
namespace SampleWebApp.Models
{
using System.Collections.Generic;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
public interface IOAuthWebSecurity
{
string GetUserName(string providerName, string providerUserId);
bool HasLocalAccount(int userId);
ICollection<OAuthAccount> GetAccountsFromUserName(string userName);
bool DeleteAccount(string providerName, string providerUserId);
AuthenticationResult VerifyAuthentication(string returnUrl);
bool Login(string providerName, string providerUserId, bool createPersistentCookie);
void CreateOrUpdateAccount(string providerName, string providerUserId, string userName);
string SerializeProviderUserId(string providerName, string providerUserId);
AuthenticationClientData GetOAuthClientData(string providerName);
bool TryDeserializeProviderUserId(string data, out string providerName, out string providerUserId);
ICollection<AuthenticationClientData> RegisteredClientData { get; }
void RequestAuthentication(string provider, string returnUrl);
}
}
IWebSecurity.cs
namespace SampleWebApp.Models
{
using System.Security.Principal;
public interface IWebSecurity
{
bool Login(string userName, string password, bool persistCookie = false);
void Logout();
string CreateUserAndAccount(string userName, string password, object propertyValues = null, bool requireConfirmationToken = false);
int GetUserId(string userName);
bool ChangePassword(string userName, string currentPassword, string newPassword);
string CreateAccount(string userName, string password, bool requireConfirmationToken = false);
IPrincipal CurrentUser { get; }
}
}
OAuthWebSecurityWrapper.cs
namespace SampleWebApp.Models
{
using System.Collections.Generic;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
public class OAuthWebSecurityWrapper : IOAuthWebSecurity
{
public string GetUserName(string providerName, string providerUserId)
{
return OAuthWebSecurity.GetUserName(providerName, providerUserId);
}
public bool HasLocalAccount(int userId)
{
return OAuthWebSecurity.HasLocalAccount(userId);
}
public ICollection<OAuthAccount> GetAccountsFromUserName(string userName)
{
return OAuthWebSecurity.GetAccountsFromUserName(userName);
}
public bool DeleteAccount(string providerName, string providerUserId)
{
return OAuthWebSecurity.DeleteAccount(providerName, providerUserId);
}
public AuthenticationResult VerifyAuthentication(string returnUrl)
{
return OAuthWebSecurity.VerifyAuthentication(returnUrl);
}
public bool Login(string providerName, string providerUserId, bool createPersistentCookie)
{
return OAuthWebSecurity.Login(providerName, providerUserId, createPersistentCookie);
}
public void CreateOrUpdateAccount(string providerName, string providerUserId, string userName)
{
OAuthWebSecurity.CreateOrUpdateAccount(providerName, providerUserId, userName);
}
public string SerializeProviderUserId(string providerName, string providerUserId)
{
return OAuthWebSecurity.SerializeProviderUserId(providerName, providerUserId);
}
public AuthenticationClientData GetOAuthClientData(string providerName)
{
return OAuthWebSecurity.GetOAuthClientData(providerName);
}
public bool TryDeserializeProviderUserId(string data, out string providerName, out string providerUserId)
{
return OAuthWebSecurity.TryDeserializeProviderUserId(data, out providerName, out providerUserId);
}
public ICollection<AuthenticationClientData> RegisteredClientData { get { return OAuthWebSecurity.RegisteredClientData; } }
public void RequestAuthentication(string provider, string returnUrl)
{
OAuthWebSecurity.RequestAuthentication(provider, returnUrl);
}
}
}
WebSecurityWrapper.cs
namespace SampleWebApp.Models
{
using System.Security.Principal;
using System.Web;
using WebMatrix.WebData;
public class WebSecurityWrapper : IWebSecurity
{
public bool Login(string userName, string password, bool persistCookie = false)
{
return WebSecurity.Login(userName, password, persistCookie);
}
public void Logout()
{
WebSecurity.Logout();
}
public string CreateUserAndAccount(string userName, string password, object propertyValues = null, bool requireConfirmationToken = false)
{
return WebSecurity.CreateUserAndAccount(userName, password, propertyValues);
}
public int GetUserId(string userName)
{
return WebSecurity.GetUserId(userName);
}
public bool ChangePassword(string userName, string currentPassword, string newPassword)
{
return WebSecurity.ChangePassword(userName, currentPassword, newPassword);
}
public string CreateAccount(string userName, string password, bool requireConfirmationToken = false)
{
return WebSecurity.CreateAccount(userName, password, requireConfirmationToken);
}
public IPrincipal CurrentUser
{
get { return HttpContext.Current.User; }
}
}
}
AccountControllerTests.cs
using System;
using System.Collections.Generic;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Web.WebPages.OAuth;
using Moq;
using SampleWebApp.Controllers;
using SampleWebApp.Models;
namespace SampleWebApp.UnitTests
{
[TestClass]
public class AccountControllerTests
{
private AccountController Controller { get; set; }
private RouteCollection Routes { get; set; }
private Mock<IWebSecurity> WebSecurity { get; set; }
private Mock<IOAuthWebSecurity> OAuthWebSecurity { get; set; }
private Mock<HttpResponseBase> Response { get; set; }
private Mock<HttpRequestBase> Request { get; set; }
private Mock<HttpContextBase> Context { get; set; }
private Mock<ControllerContext> ControllerContext { get; set; }
private Mock<IPrincipal> User { get; set; }
private Mock<IIdentity> Identity { get; set; }
//added for service constructor parameters
private Mock<IUserAccountService> UserAccountService { get; set; }
private Mock<IUserService> UserService { get; set; }
private Mock<IParentPortalService> ParentPortalService { get; set; }
public AccountControllerTests()
{
WebSecurity = new Mock<IWebSecurity>(MockBehavior.Strict);
OAuthWebSecurity = new Mock<IOAuthWebSecurity>(MockBehavior.Strict);
//added for services constructor parameters
UserAccountService= new Mock<IUserAccountService>(MockBehavior.Strict);
UserService= new Mock<IUserService>(MockBehavior.Strict);
ParentPortalService= new Mock<IParentPortalService>(MockBehavior.Strict);
//end
Identity = new Mock<IIdentity>(MockBehavior.Strict);
User = new Mock<IPrincipal>(MockBehavior.Strict);
User.SetupGet(u => u.Identity).Returns(Identity.Object);
WebSecurity.SetupGet(w => w.CurrentUser).Returns(User.Object);
Routes = new RouteCollection();
RouteConfig.RegisterRoutes(Routes);
Request = new Mock<HttpRequestBase>(MockBehavior.Strict);
Request.SetupGet(x => x.ApplicationPath).Returns("/");
Request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
Request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
Response = new Mock<HttpResponseBase>(MockBehavior.Strict);
Context = new Mock<HttpContextBase>(MockBehavior.Strict);
Context.SetupGet(x => x.Request).Returns(Request.Object);
Context.SetupGet(x => x.Response).Returns(Response.Object);
Controller = new AccountController(WebSecurity.Object, OAuthWebSecurity.Object);
//for service constructor parameters
//Controller = new AccountController(UserService.Object, ParentPortalService.Object);
Controller.ControllerContext = new ControllerContext(Context.Object, new RouteData(), Controller);
Controller.Url = new UrlHelper(new RequestContext(Context.Object, new RouteData()), Routes);
}
[TestMethod]
public void Login_UserCanLogin()
{
string returnUrl = "/Home/Index";
string userName = "user";
string password = "password";
WebSecurity.Setup(s => s.Login(userName, password, false)).Returns(true);
var model = new LoginModel
{
UserName = userName,
Password = password
};
var result = Controller.Login(model, returnUrl) as RedirectResult;
Assert.IsNotNull(result);
Assert.AreEqual(returnUrl, result.Url);
}
}
}