Search code examples
c#asp.net-coremoqentity-framework-corexunit2

Unit Test Save Changes failing


Frameworks

.NETCoreApp 1.1
EF Core 1.1.1
Xunit 2.2.0
Moq 4.7.8

Controller Post Method
_yourRepository is injected in the controllers constructor and is of type IYourRepository

[HttpPost(Name = "CreateMethod")]
public async Task<IActionResult> CreateMethod([FromBody] ObjectForCreationDto objectDto)
{
    if (objectDto== null)
    {
        return BadRequest();
    }

    if (!ModelState.IsValid)
    {
        return BadRequest();
    }

    await _yourRespository.CreateObject(objectDto);

    if (!await _yourRespository.Save())
    {
        throw new Exception("Creating this object failed on save.");
    }            

    return Ok();
}

Unit Test that fails

[Fact]
public async Task CreateObject_WhenGoodDtoReceived_SuccessStatusReturned()
{
    // Arrange
    var mockRepo = new Mock<IYourRepository>();
    var controller = new YourController(mockRepo.Object);
    var objectForCreationDto = new ObjectForCreationDto { Code = "0001", Name = "Object One" };

    // Act
    var result = await controller.CreateObject(objectForCreationDto);

    // Assert
    Assert.IsType<OkObjectResult>(result);
}

The test fails because the line

if (!await _yourRespository.Save())

Always evaluates to true. When it evaluates to true you can see that the code throws an error (which is handled by middleware)

_yourRepository.Save() method

public async Task<bool> Save()
{
    return (await _yourContext.SaveChangesAsync() >= 0);
}

I'm not sure how to solve the problem and I'm not 100% sure why it is failing.

Is it because the mocked IYourRepository interface doesn't include an implementation of the Save method?

If so, does that mean to test the Post method I would need to mock my DbContext and construct my YourRepository object using it?

Any explanation as to why this is failing and how to rectify it would be much appreciated


Solution

  • You need to setup the repo to return a proper task from the async method. Moq allows this using ReturnsAsync

    [Fact]
    public async Task CreateObject_WhenGoodDtoReceived_SuccessStatusReturned()
    {
        // Arrange
        var mockRepo = new Mock<IYourRepository>();
        mockRepo.Setup(_ => _.Save()).ReturnsAsync(true);//<-- ADD THIS
        var controller = new YourController(mockRepo.Object);
        var objectForCreationDto = new ObjectForCreationDto { Code = "0001", Name = "Object One" };
    
        // Act
        var result = await controller.CreateObject(objectForCreationDto);
    
        // Assert
        Assert.IsType<OkObjectResult>(result);
    }