Get an object from a service to allow test to run using xUnit and Moq

This is probably due to my lack of understanding as I’m new to xUnit and Moq but I’m trying to test a post method in my controller, however in the controller, I have this line of code:

var user = await _mapModelService.MapModelForNewUser(viewModel);

This will pass the ViewModel to the service where it maps the ViewModel properties to a new Model ready for it to be written to the database later.

In the test, I’m trying to use Moq to use the service and return a new Model. This code I have is like so:

mapModelService.Setup(x => x.MapModelForNewUser(new NewUserVm())).ReturnsAsync(new User()
{
    UserId = 1
});

All I need is the id so I can test the route values once it’s finished, however the user object in the controller is null and the test fails with a NullReferenceException. I’m not trying to test the object the service returns, it’s just so the test runs.

Where have I gone wrong?

EDIT: The suggested answer does not answer my question, it appears to be very similar to what I’m already doing. I’ve tried creating new instances of ViewModel and Model and giving them arbitrary values and passing those instead, with the same result.

EDIT 2: The service is asynchronous, id that makes a difference how this is called but I was under the impression ReturnsAsync() handles this.

EDIT 3: Here’s the full test.

        [Fact]
        public async Task NewUser_ShouldRedirectToNewCreatedUserWhenModelStateIsValid_WithUserDetailsVm()
        {
            // Arrange
            var logger = new Mock<ILogger<UserController>>();
            var vmService = new Mock<IViewModelService>();
            var userRepo = new Mock<IUserRepo>();
            var mapModelService = new Mock<IMapModelService>();

            var userController = new UserController(logger.Object, vmService.Object, userRepo.Object, mapModelService.Object);
            var redirectToRouteResult = await userController.NewUser(It.IsAny<NewUserVm>()) as RedirectToRouteResult;
            

            // Act
            mapModelService.Setup(x => x.MapModelForNewUser(It.IsAny<NewUserVm>()))
                .ReturnsAsync(new User()
                {
                    UserId = 1
                });

            userController.ModelState.Clear();

            // Assert
            Assert.NotNull(redirectToRouteResult);
            Assert.False(redirectToRouteResult.Permanent);
            Assert.Equal("UserDetails", redirectToRouteResult.RouteValues["Action"]);
            Assert.Equal("User", redirectToRouteResult.RouteValues["Controller"]);
            Assert.Equal(1, redirectToRouteResult.RouteValues["id"]);
            Assert.Equal("note", redirectToRouteResult.RouteValues["requiredTab"]);
        }

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

If you do not care about the viewmodel being passed in then use It.IsAny<NewUserVm>() in the setup.

Also the Setup needs to be done before invoking the subject under test

// Arrange

// ...omitted for brevity

mapModelService
    .Setup(x => x.MapModelForNewUser(It.IsAny<NewUserVm>())) //<--NOTE THE ARGUMENT MATCHER
    .ReturnsAsync(new User() {
        UserId = 1
    });

var viewModel = new NewUserVm();

// Act
var redirectToRouteResult = await userController.NewUser(viewModel) as RedirectToRouteResult;
       
// Assert

// ...

The original setup was done with a specific instance that will never be used when exercising the test. Thus the mock will never behave as you would expect.

Reference Moq Quickstart for a better understanding of how to use it.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x