Reputation: 3879
I am new to Moq and I am trying to implement 2 tests that check for a HttpStatusCode.NotModified
and HttpStatusCode.Ok
. However, the latter passes its test, but the former doesn't and returns the exception:
Moq.MockException : Expected invocation on the mock once, but was 0 times: x => x.UpdateStateAsync(It.Is(y => y == RedisServiceModel))
Here is the HttpStatusCode.Ok
which passes:
[Fact]
public void UpdateState_StateHasBeenUpdated_HttpOk()
{
//arrange
var state = new RedisServiceModel();
var redisServiceMock = new Mock<IRedisService>();
redisServiceMock.Setup(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == state))).ReturnsAsync(state);
var testController = new TestController(redisServiceMock.Object);
// act
var statusResult = testController.UpdateStates(state);
// assert
redisServiceMock.Verify(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == state)));
Assert.True(statusResult.Result is HttpStatusCode.OK);
}
Here is the HttpStatusCode.NotModified
which throws the exception:
[Fact]
public void UpdateState_StateHasNotBeenModified_HttpNotModified()
{
//arrange
var state = new RedisServiceModel();
var redisServiceMock = new Mock<IRedisService>();
redisServiceMock.Setup(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == state))).ReturnsAsync(state);
var testController = new TestController(redisServiceMock.Object);
// act
var statusResult = testController.UpdateStates(null);
// assert
redisServiceMock.Verify(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == state)), Times.Once);
Assert.True(statusResult.Result is HttpStatusCode.NotModified);
}
Here is the PUT
api call:
[HttpPut]
[Route("updatestates")]
public async Task<HttpStatusCode> UpdateStates(RedisServiceModel update)
{
RedisServiceModel updateState = await _redisService.UpdateStateAsync(update);
if (updateState != null)
{
return HttpStatusCode.OK;
}
return HttpStatusCode.NotModified;
}
I'm guessing it's because I'm passing in null
here testController.UpdateStates(null)
. I did try wrapping everything in the UpdateStates
API method to null
check the update
argument, but this still yielded the same exception. If anymore code is needed let me know and I'll edit this post.
Upvotes: 4
Views: 7169
Reputation: 247631
The subject should be awaited, otherwise the assertion could be made before the subject has completed the expected behavior
The mock should also be configured to return the passed argument to mimic the expected behavior of the actual implementation
[Fact]
public async Task UpdateState_StateHasNotBeenModified_HttpNotModified() {
//arrange
var state = new RedisServiceModel();
var redisServiceMock = new Mock<IRedisService>();
redisServiceMock
.Setup(x => x.UpdateStateAsync(It.IsAny<RedisServiceModel>()))
.ReturnsAsync(x => x);
var testController = new TestController(redisServiceMock.Object);
// act
var statusResult = await testController.UpdateStates(null);
// assert
redisServiceMock.Verify(x => x.UpdateStateAsync(
It.Is<RedisServiceModel>(y => y == null)),
Times.Once);
Assert.True(statusResult is HttpStatusCode.NotModified);
}
The same should also have been done for the other test
[Fact]
public async Task UpdateState_StateHasBeenUpdated_HttpOk()
{
//arrange
var state = new RedisServiceModel();
var redisServiceMock = new Mock<IRedisService>();
redisServiceMock
.Setup(x => x.UpdateStateAsync(It.Is<RedisServiceModel>()))
.ReturnsAsync(x => x);
var testController = new TestController(redisServiceMock.Object);
// act
var statusResult = await testController.UpdateStates(state);
// assert
redisServiceMock.Verify(x => x.UpdateStateAsync(
It.Is<RedisServiceModel>(y => y == state)));
Assert.True(statusResult is HttpStatusCode.OK);
}
That said, the subject action should be refactored to follow proper syntax for controllers.
Assuming the controller is derived from ControllerBase
it would have access to helper methods for action results.
[HttpPut]
[Route("updatestates")]
public async Task<IActionResult> UpdateStates(RedisServiceModel update) {
RedisServiceModel updateState = await _redisService.UpdateStateAsync(update);
if (updateState != null) {
return Ok();
}
return StausCode((int)HttpStatusCode.NotModified);
}
Upvotes: 3
Reputation: 26460
The problem is that you are checking between null
and state
which are not equal. The function has been called but with null, instead of state (the equality is on the reference).
Try with this:
[Fact]
public void UpdateState_StateHasNotBeenModified_HttpNotModified()
{
//arrange
var state = new RedisServiceModel();
var redisServiceMock = new Mock<IRedisService>();
redisServiceMock.Setup(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == state))).ReturnsAsync(state);
var testController = new TestController(redisServiceMock.Object);
// act
var statusResult = testController.UpdateStates(null);
// assert
redisServiceMock.Verify(x => x.UpdateStateAsync(It.Is<RedisServiceModel>(y => y == null)), Times.Once);
Assert.True(statusResult.Result is HttpStatusCode.NotModified);
}
Upvotes: 1