Writing unit tests that require database access via my CustomMembershipProvider.
edit
-
public class CustomMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
using (var usersContext = new UsersContext())
{
var requiredUser = usersContext.GetUser(username, password);
var userApproved = usersContext.GetUserMem(username);
if (userApproved == null) return false;
return (requiredUser != null && userApproved.IsApproved != false);
}
}
}
[TestFixture]
public class AccountControllerTest
{
[Test]
public void ShouldNotAcceptInvalidUser()
{
// OPTION1
Mock<IMembershipService> membership = new Mock<IMembershipService>();
//OPTION2
// Mock<AccountMembershipService> membership = new Mock<AccountMembershipService>();
membership.Setup(m => m.ValidateUser(It.IsAny<string>(), It.IsAny<string>()))
.Returns(false);
var logonModel = new LoginModel() { EmailorUserName = "connorgerv", Password = "pasdsword1" };
var controller = new AccountController(membership.Object);
// Act
var result = controller.Login(logonModel,"Index") as RedirectResult;
// Assert
Assert.That(result.Url, Is.EqualTo("Index"));
Assert.False(controller.ModelState.IsValid);
Assert.That(controller.ModelState[""],
Is.EqualTo("The user name or password provided is incorrect."));
}
[Test]
public void ExampleForMockingAccountMembershipService()
{
var validUserName = "connorgerv";
var validPassword = "passwordd1";
var stubService = new Mock<CustomMembershipProvider>();
bool val = false;
stubService.Setup(x => x.ValidateUser(validUserName, validPassword)).Returns(true);
Assert.IsTrue(stubService.Object.ValidateUser(validUserName, validPassword));
}
}
public class AccountController : Controller
{
public IMembershipService MembershipService { get; set; }
public AccountController(IMembershipService service){
MembershipService=service;
}
protected override void Initialize(RequestContext requestContext)
{
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
}
public ActionResult Index()
{
return RedirectToAction("Profile");
}
public ActionResult Login()
{
if (User.Identity.IsAuthenticated)
{
//redirect to some other page
return RedirectToAction("Index", "Home");
}
return View();
}
//
// POST: /Account/Login
[HttpPost]
public ActionResult Login(LoginModel model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.EmailorUserName, model.Password))
{
SetupFormsAuthTicket(model.EmailorUserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
public class AccountMembershipService : IMembershipService
{
private readonly MembershipProvider _provider;
public AccountMembershipService()
: this(null)
{
}
public AccountMembershipService(MembershipProvider provider)
{
_provider = provider ?? Membership.Provider;
}
public virtual bool ValidateUser(string userName, string password)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
return _provider.ValidateUser(userName, password);
}
}
Membership in web.config of main application
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear />
<add name="CustomMembershipProvider" type="QUBBasketballMVC.Infrastructure.CustomMembershipProvider" connectionStringName="UsersContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
public class CustomMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
using (var usersContext = new UsersContext())
{
var requiredUser = usersContext.GetUser(username, password);
var userApproved = usersContext.GetUserMem(username);
if (userApproved == null) return false;
return (requiredUser != null && userApproved.IsApproved != false);
}
}
}
What happens when I run ShouldNotAcceptInvalidUser()
with Option1 uncommented I can see that MembershipService is a Mock<IMembershipService>
in the AccountController but it never steps into MembershipService.ValidateUser on the login Action.
When I run with option2 uncommented the same thing happens except MembershipService is Mock<AccountMembershipService>
in the accountcontroller and it hits the AccountMembership Contstructor with null parameters, which in turn sets is to SqlMembershipProvider
as Membership.Provider
is System.Web.Security.SqlMembershipProvider
Also ExampleForMockingAccountMembershipService()
doesn't seem to hit the ValidateUser
method at all in CustomMembershipProvider
and always returns true.
Hopefully this is enough to see where i'm going wrong!! :/