Search code examples
c#unit-testing.net-coremoqautofixture

NRE in a unit test when await a mocked method


I'm trying to build a unit test for a .net Core 3 Web API with mstest.

I'm also using:

  • Autofixture
  • Moq
  • AutoFixture.AutoMoq

This unit test should return a NotFound() response when no beer are found.

    private IFixture _fixture;
    private BeerController _beerController;
    private Mock<IBeerService> _mockBeerService;

    [TestInitialize]
    public void Initialize()
    {
        _fixture = new Fixture().Customize(new AutoMoqCustomization());
        _mockBeerService = _fixture.Freeze<Mock<IBeerService>>();
        _beerController = _fixture.Create<BeerController>();
    }

    [TestMethod]
    public async Task WhenCallGetBeerWithoutMatchReturnNotFound404()
    {
        //Arrange
        int beerId = _fixture.Create<int>();
        _mockBeerService.Setup(x => x.GetBeer(It.IsAny<int>())).Returns((Task<Beer>)null);

        //Act
        var actionResult = await _beerController.Get(beerId);

        //Assert
        Assert.IsInstanceOfType(actionResult.Result, typeof(NotFoundResult));
    }

That's the function I'm trying to test:

    [HttpGet("{beerId:int}")]
    public async Task<ActionResult<beer>> Get(int beerId)
    {
        try
        {
            var beer = await _beerService.Getbeer(beerId);
            if (beer == null) return NotFound();

            return Ok(beer);
        }
        catch (Exception)
        {
            return BadRequest();
        }
    }

But I'm running into Object reference not set to an instance of an object. exception on this line of code: var beer = await _biereService.Getbeer(beerId);

This is the stack trace: at BeerProject.Controllers.BeerController.<Get>d__2.MoveNext() in F:\DevProjects\Repos\API_BeerProject\BeerProject\Controllers\BeerController.cs:line 29

I tested return Ok(beer) with this test :

    [TestMethod]
    public async Task WhenCallGetBeerWithMatchReturnOk200()
    {
        //Arrange
        int beerId = _fixture.Create<int>();
        var beer = _fixture.Create<Task<Beer>>();

        _mockBeerService.Setup(x => x.GetBeer(It.IsAny<int>())).Returns(beer);
        //Act
        var actionResult = await _beerController.Get(beerId);

        //Assert
        Assert.IsInstanceOfType(actionResult.Result, typeof(OkObjectResult));
    }  

and it is working fine.

so I'm guessing that he does not like the .Returns((Task<Beer>)null) in WhenCallGetBeerWithoutMatchReturnNotFound404()


Solution

  • In your controller, you're assuming that GetBeer returns a non-null task, because you're unconditionally await it. You then check the result, the beer, to see if it's null or not:

    var beer = await _beerService.Getbeer(beerId);
    if (beer == null) return NotFound();
    

    In this line, you are not returning a task with null beer, your are returning a null task:

    _mockBeerService.Setup(x => x.GetBeer(It.IsAny<int>())).Returns((Task<Beer>)null);
    

    As such, awaiting the null is causing your NullReferenceException.

    If you want to return a null beer as the result of a Task, you will need instead to use:

    _mockBeerService.Setup(x => x.GetBeer(It.IsAny<int>())).Returns(Task.FromResult<Beer>(null));
    

    Or even:

    _mockBeerService.Setup(x => x.GetBeer(It.IsAny<int>())).ReturnsAsync(null);