Unit Testing Async Controller Method Returning Null with NUnit and Moq

I have a .NET Core API Framework 6.0, I'm writing tests an Async Controller method using NUnit Framework I'm getting null value returned by the Controller Authentication method. When I make a similar call from Postman there is response. I assume my Moq is missing something but I have followed documentation and cannot figure out the issue.

//User Controller
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    [AllowAnonymous]
    [HttpPost("authenticate")]
    public async Task<IActionResult> Authenticate([FromBody] UserRequest userRequest)
    {
        try
        {
            var response = await _userService.Authenticate(userRequest); //Authenticate method is not being called, response is NULL here
            return Ok(new ApiResponse<UserResponse>().Success(response));
        }
        catch (Exception ex)
        {
            return betServerError(ex);
        }
    }

The Authenticate method is as below, the breakpoint on Line 1 is not being hit.

public async Task<UserResponse> Authenticate(UserRequest userRequest)
    {
        var user = _context.Users.Where(x => x.Email == userRequest.Email).FirstOrDefault(); //Breakpoint here is not being hit
        bool valid = false;

        if (user == null)
            throw new HttpException(HttpStatusCode.Unauthorized, "Username or password incorrect");

        //Other code ......
        
     return new UserResponse
        {
            Id = user.Id,
            Email = user.Email,
            Token = tokenString
        };
    }

UserTest.cs looks as follows:

Mock<IUserService> UserServiceMock = new Mock<IUserService>();

    [SetUp]
    public void Setup()
    {

    }
    [Test]
    public async Task should_Login()
    {
        //Arrange
        var user = new UserResponse
        {
            Id = 1,
            Email = "username@gmail.com",
            Token = "TEST_TOKEN"
        };
        UserServiceMock.Setup(x => x.Authenticate(new UserRequest { Email = "username@gmail.com", Password = "password" }))
            .Returns(Task.Run(() => user));
        var UserController = new UserController(UserServiceMock.Object);

        //Act
        var result = await UserController.Authenticate(new UserRequest { Email = "username@gmail.com", Password = "password1" }); //result here doesnot contain the response I expect, it has a null object
        
        //Assert
        Assert.IsNotNull(result);
        Assert.AreEqual(HttpStatusCode.OK, GetHttpStatusCode(result));
    }

1 answer

  • answered 2022-03-07 18:06 Stephen Cleary

    The UserRequest instance you're passing into Authenticate is a different instance than what you're setting up your mock to expect. So, since the inputs don't match, the mock is not executed, and the default mock behavior takes over.

    Either remove the mock conditional (i.e., use It.IsAny<UserRequest>()), or pass the same instance to your mock and your controller method.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum