Ошибка при выполнении модульного теста для регистрационного кода ASP.Net MVC, который использует ASP.Net Identity

Я новичок в ASP.Net MVC а также Identity,

У меня есть следующий метод модульного тестирования.

[TestMethod]
public void SignUp()
{
    try
    {
        var dummyUser = new ApplicationUser() { UserName = "xyz", Email = "xyz@gmail.com" };

        ViewModels.RegisterViewModel rvm = new ViewModels.RegisterViewModel { Name = "abc", Email = "abc@yahoo.com", 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(); }
}

Оригинальный метод SignUp, который отлично работает, когда я запускаю его в режиме отладки, но выдает ошибку, если выполняется из модульного теста.

[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);
    }
}

Я получаю следующую ошибку, в то время как IdentityResult addResult = await UserManager.AddToRoleAsync(appUser.Id, "I") выполняется из кода выше через модульный тест.

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()

Что здесь происходит не так, что вызывает ошибку выше.

1 ответ

Решение

Мне кажется, вам нужно установить результат для метода IUserStore.GetRolesAsync.

Метод UserManager.AddToRoleAsync вызывает IUserStore.GetRolesAsync и вызывает метод "Содержит" возвращенной коллекции ролей.

Поскольку в модульном тесте нет результата для этого метода, он возвращает значение по умолчанию, которое вызвало возникновение этого исключения.

Ниже приведен код, для которого я настроил результат IUserStore.GetRolesAsync вернуть пустой список ролей.

[TestMethod]
public void SignUp()
{
    try
    {
        var dummyUser = new ApplicationUser() { UserName = "xyz", Email = "xyz@gmail.com" };

        ViewModels.RegisterViewModel rvm = new ViewModels.RegisterViewModel { Name = "abc", Email = "abc@yahoo.com", 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(); }
}
Другие вопросы по тегам