tmndungu
tmndungu

Reputation: 358

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 = "[email protected]",
            Token = "TEST_TOKEN"
        };
        UserServiceMock.Setup(x => x.Authenticate(new UserRequest { Email = "[email protected]", Password = "password" }))
            .Returns(Task.Run(() => user));
        var UserController = new UserController(UserServiceMock.Object);

        //Act
        var result = await UserController.Authenticate(new UserRequest { Email = "[email protected]", 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));
    }

Upvotes: 0

Views: 1041

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456437

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.

Upvotes: 1

Related Questions