rikencpatel
rikencpatel

Reputation: 53

Error while running unit test on ASP.Net MVC registraton code which uses ASP.Net Identity

I am new to ASP.Net MVC and Identity.

I have following unit test method.

[TestMethod]
public void SignUp()
{
    try
    {
        var dummyUser = new ApplicationUser() { UserName = "xyz", Email = "[email protected]" };

        ViewModels.RegisterViewModel rvm = new ViewModels.RegisterViewModel { Name = "abc", Email = "[email protected]", Password = "123456" };

        var store = new Mock<IUserStore<ApplicationUser>>();

        store.As<IUserPasswordStore<ApplicationUser>>()
            .Setup(x => x.FindByIdAsync(It.IsAny<string>()))
            .ReturnsAsync(new ApplicationUser() { Id = "id" });
        store.Setup(x => x.CreateAsync(dummyUser)).Returns(Task.FromResult(IdentityResult.Success));

        store.As<IUserRoleStore<ApplicationUser>>().Setup(x => x.AddToRoleAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())).Returns(Task.FromResult(IdentityResult.Success));
        store.As<IUserRoleStore<ApplicationUser>>().Setup(x => x.IsInRoleAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())).ReturnsAsync(true);
        store.As<IRoleStore<IdentityRole>>().Setup(x => x.CreateAsync(new IdentityRole("I"))).Returns(Task.FromResult(IdentityResult.Success));

        //var roleStore = new Mock<IRoleStore<IdentityRole>>();
        //roleStore.As<IRoleStore<IdentityRole>>();
        //roleStore.Setup(x => x.CreateAsync(new IdentityRole("I"))).Returns(Task.FromResult(IdentityResult.Success));
        //var testRoleManager = new ApplicationRoleManager(roleStore.Object);

        //to register usertokenprovider as it is needed to send confirmation email    
        var provider = new  Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("Sample");
        var testUserManager = new ApplicationUserManager(store.Object);
        testUserManager.UserTokenProvider =new DataProtectorTokenProvider<ApplicationUser>(provider.Create("ASP.NET Identity"));

        // mocking IAuthenticationManager
        var mockAuthenticationManager = new Mock<IAuthenticationManager>();
        mockAuthenticationManager.Setup(am => am.SignOut());
        mockAuthenticationManager.Setup(am => am.SignIn());

        //mocking Context
        var routes = new System.Web.Routing.RouteCollection();
        ProChartSiteMVC.RouteConfig.RegisterRoutes(routes);

        var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
        request.SetupGet(x => x.ApplicationPath).Returns("/");
        request.SetupGet(x => x.Url).Returns(new Uri("http://localhost:1431/a", UriKind.Absolute));
        request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());

        var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
        response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost:1431/post1");

        var context = new Mock<HttpContextBase>(MockBehavior.Strict);
        context.SetupGet(x => x.Request).Returns(request.Object);
        context.SetupGet(x => x.Response).Returns(response.Object);

        var testSignInManager = new ApplicationSignInManager(testUserManager,mockAuthenticationManager.Object);

        BussinessLayer bussinessLayer = new BussinessLayer(db);

        AccountController controller = new AccountController(testUserManager,testSignInManager, bussinessLayer);
        var UrlHelperMock = new Mock<UrlHelper>();
        controller.Url = UrlHelperMock.Object;

        controller.ControllerContext = new ControllerContext(context.Object, new System.Web.Routing.RouteData(), controller);

        var result = controller.SignUp(rvm) as Task<ActionResult>;
        var viewresult = result.Result;
        Assert.IsNotNull(result);
    }
    catch (Exception ex) { string str = ex.ToString(); }
}

Original SignUp method which works fine when I run it debug mode but gives error if executed from unit test.

[HttpPost]
public async Task<ActionResult> SignUp(RegisterViewModel rvm)
{
    if (ModelState.IsValid)
    {               
        var appUser = new ApplicationUser();
        appUser.UserName = bLayer.GenerateInvestarID(rvm.Email);
        appUser.Email = rvm.Email;
        appUser.Name = rvm.Name;
        appUser.LockoutEnabled = true;
        appUser.InstituteCode = "10";
        try
        {
            var result = await UserManager.CreateAsync(appUser, rvm.Password);
            if (result.Succeeded)
            {
                IdentityResult addResult = await UserManager.AddToRoleAsync(appUser.Id, "I");
                await SignInManager.SignInAsync(appUser, isPersistent: false, rememberBrowser: false);
                string code = await UserManager.GenerateEmailConfirmationTokenAsync(appUser.Id);
                var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = appUser.Id, code = code }, protocol: Request.Url.Scheme);
                await UserManager.SendEmailAsync(appUser.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
                return RedirectToAction("Thankyou");
            }
            else
            {
                AddErrors(result);
                return PartialView("_PartialSignUp", rvm);
            }
        }
        catch(Exception ex)
        {
            ModelState.AddModelError("CredentialError", ex.Message);
            return PartialView("_PartialSignUp", rvm);
        }
    }
    else
    {
        ModelState.AddModelError("CredentialError", "Invalid Details");
        return PartialView("_PartialSignUp", rvm);
    }
}

I get following error while IdentityResult addResult = await UserManager.AddToRoleAsync(appUser.Id, "I") is executed from above code through unit test.

System.NullReferenceException was caught
  _HResult=-2147467261
  _message=Object reference not set to an instance of an object.
  HResult=-2147467261
  IsTransient=false
  Message=Object reference not set to an instance of an object.
  Source=Microsoft.AspNet.Identity.Core
  StackTrace:
       at Microsoft.AspNet.Identity.UserManager`2.<AddToRoleAsync>d__83.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       at SiteMVC.Controllers.AccountController.<SignUp>d__0.MoveNext()

What is going wrong here which causes above error.

Upvotes: 2

Views: 379

Answers (1)

Chetan
Chetan

Reputation: 6891

To me it looks like you need to Setup result for IUserStore.GetRolesAsync method.

UserManager.AddToRoleAsync method calls IUserStore.GetRolesAsync and calls 'Contains' method on the returned collection of the roles.

Since there is no result is setup for this method in unit test it returns null as the default which caused this exception to happen.

Following is the code I have setup the result for IUserStore.GetRolesAsync to return empty list of roles.

[TestMethod]
public void SignUp()
{
    try
    {
        var dummyUser = new ApplicationUser() { UserName = "xyz", Email = "[email protected]" };

        ViewModels.RegisterViewModel rvm = new ViewModels.RegisterViewModel { Name = "abc", Email = "[email protected]", Password = "123456" };

        var store = new Mock<IUserStore<ApplicationUser>>();

        var roles = new List<string>(); // Populate this list as per your need.

        store.As<IUserPasswordStore<ApplicationUser>>()
            .Setup(x => x.FindByIdAsync(It.IsAny<string>()))
            .ReturnsAsync(new ApplicationUser() { Id = "id" });

        store.Setup(x => x.CreateAsync(dummyUser)).Returns(Task.FromResult(IdentityResult.Success));

        //Setting up the result for GetRoleAsync method to return roles collection.
        store.As<IUserRoleStore<ApplicationUser>>().Setup(x => x.GetRolesAsync(It.IsAny<ApplicationUser>())).ReturnsAsync(roles);

        //Rest of the unit test code
    }
    catch (Exception ex) { string str = ex.ToString(); }
}

Upvotes: 3

Related Questions