1

I am trying to Unit Test that a controller action returns the correct view. I am using .NET Core, Moq, and NUnit.

I want test the default ManageController,

The Constructor is below,

public ManageController( UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IEmailSender emailSender, ILogger<ManageController> logger, UrlEncoder urlEncoder) { _userManager = userManager; _signInManager = signInManager; _emailSender = emailSender; _logger = logger; _urlEncoder = urlEncoder; } 

And am trying to Unit Test the following Index Action, and Assert that it returns the correct ViewModel when successful. (And will add other paths that return different ViewModels in future)

[HttpGet] public async Task<IActionResult> Index() { var user = await _userManager.GetUserAsync(User); if (user == null) { throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); } var model = new IndexViewModel { Username = user.UserName, Email = user.Email, PhoneNumber = user.PhoneNumber, IsEmailConfirmed = user.EmailConfirmed, StatusMessage = StatusMessage }; return View(model); } 

After many attempts, my closest solution is as follows,

I have mocked, UserManager, and Setup the GetUserASync method with a ClaimsPrincipal with the Id "1". I have also set the HttpContext to use the same ClaimsPrincipal and passed that the the controller.

As the Action is async, I was forced to make the test method async. Currently the test fails due to the async Task that is returned being null. I can't see if the rest of the test passes as I can't get past this error.

[Test] public async Task Index_UserExists_ReturnsViewAsync() { var mockUserStore = new Mock<IUserStore<ApplicationUser>>(); var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockUserStore.Object, null, null, null, null, null, null, null, null); var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, "1"), })); mockUserManager.Setup(x => x.GetUserAsync(user)); var controller = new ManageController(mockUserManager.Object, null, null, null, null) { ControllerContext = new ControllerContext() { HttpContext = new DefaultHttpContext() { User = user } } }; //Act var result = await controller.Index(); //Assert Assert.IsInstanceOf<ViewResult>(result); } 

1 Answer 1

1

Set up the mock to return a task so that it can be awaited and allow the code to flow as intended

//... var appUser = new ApplicationUser { //...populate as needed } mockUserManager .Setup(_ => _.GetUserAsync(user)) .ReturnsAsync(appUser); // Allows mocked member to be awaited and return desired type //... 
Sign up to request clarification or add additional context in comments.

1 Comment

Perfect thank you. I had tried mockUserManager .Setup(_ => _.GetUserAsync(user)) .Returns(appUser); but hit what now feels like an obvious error with async returing a task not a user. didnt think to make it RetrunAsync()

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.