2

I have been having trouble mocking some objects that are scattered around the AccountsController from the default project in ASP.NET 5 and it makes it so I can't unit test the controllers. For example, I am trying to mock up the code for the Register action.

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser
            {
                FirstName = model.FirstName, LastName = model.LastName, UserName = model.Email, Email = model.Email,
                IsActive = false, NewRequest = true
            };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                var email = _settings.GetEmailLogic();// EmailLogic(_settings);
                var emailuser = new VGSEmail(_settings)
                {
                    Id = user.Id,
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    ToEmail = new List<string> {model.Email},
                    FromEmail = _settings.GetFromEmail(),
                    Subject = EmailMessages.RegisterSubject(),
                    Body = EmailMessages.RegisterMessage(model.FirstName)
                };
                var message = email.CreateMailMessage(emailuser);
                email.Send(message);
                await SignInManager.SignInAsync(user, false, false);

                // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
                // Send an email with this link
                // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                return RedirectToAction("SelectOrganization");
            }

            AddErrors(result);
        }

I get to UserManager.CreateAsync and it dies from null. So I try the following:

var userManager = new Mock<ApplicationUserManager>();
        var identityresult = new Mock<IdentityResult>();
        identityresult.Setup(s => s.Succeeded).Returns(true);

        userManager.Setup(s => s.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
            .ReturnsAsync(Task.FromResult(identityresult);

But that second line will not compile and keeps complaining about :

'ISetup>' does not contain a definition for 'ReturnsAsync' and the best extension method overload 'SequenceExtensions.ReturnsAsync>>(ISetupSequentialResult>>>, Task>)' requires a receiver of type 'ISetupSequentialResult>>>' OnlineRepoWebSite.Tests

I know it contains a definition for ReturnsAsync because I use it all the time.

For example, the following work fine:

userManager.Setup(s => s.FindById(It.IsAny<string>())).Returns(new ApplicationUser());
        userManager.Setup(s => s.FindByIdAsync(It.IsAny<string>())).Returns(Task.FromResult(new ApplicationUser()));

But I am also having similar trouble with SignInManage. For example, the second line won't compile either.

var signInManager = new Mock<ApplicationSignInManager>(userManager, authenticationManager.Object);
        signInManager.Setup(s => s.PasswordSignInAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(),It.IsAny<bool>()))
            .ReturnsAsync(Task.FromResult(SignInStatus.Success));

Can anyone point out what I am doing wrong? Even better if any has a complete unit test of the default AccountController in MVC I would be greatly in your debt in case I run into more issues later.

ArunPratap
  • 4,816
  • 7
  • 25
  • 43
done_merson
  • 2,800
  • 2
  • 22
  • 30
  • When calling `ReturnsAsync` return the actual return object not a `Task`. ie: `.ReturnsAsync(identityresult);` and also for the other one `.ReturnsAsync(SignInStatus.Success);` – Nkosi Mar 14 '19 at 23:03

1 Answers1

1

When calling ReturnsAsync return the actual return object not a Task. ie:

userManager
    .Setup(_ => _.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
    .ReturnsAsync(identityresult); //<-- This here

and also for the other one

signInManager
    .Setup(_ => _.PasswordSignInAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(),It.IsAny<bool>()))
    .ReturnsAsync(SignInStatus.Success);

.ReturnsAsync(TValue) is basically a wrapper for .Returns(Task.FromResult(TValue))

As for making the controller more testable, that is a broad topic.

Maybe the answer I gave here

Moving ApplicationUser and other models out of MVC project

might help but it does require a lot of refactoring to make the code more SOLID.

Nkosi
  • 235,767
  • 35
  • 427
  • 472