Unit Test Save Changes failing

asp.net-core c# entity-framework-core moq xunit2

Question

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

1
1
4/21/2017 10:45:54 AM

Accepted Answer

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);
}
2
4/21/2017 10:07:47 AM

Popular Answer

Replace new Mock<IYourRepository>(); with new Mock<IYourRepository>(MockBehavior.Strict); - now it will throw exceptions when any method without Setup is called.

Obviously, you should not check (assert) something (like return values) you do not determined.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow