Moq 异常:预期对模拟调用一次,但为 0 次... - .Net Core 3.1 with xUnit

Moq Exception: Expected invocation on the mock once, but was 0 times... - .Net Core 3.1 with xUnit

我是最小起订量的新手,我正在尝试实施 2 个检查 HttpStatusCode.NotModifiedHttpStatusCode.Ok 的测试。但是,后者通过了测试,而前者没有,returns 异常:

Moq.MockException : Expected invocation on the mock once, but was 0 times: x => x.UpdateStateAsync(It.Is(y => y == RedisServiceModel))

这是通过的HttpStatusCode.Ok

        [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);
        }

这是抛出异常的HttpStatusCode.NotModified

        [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);
        }

这是 PUT api 调用:

        [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;
        }

我猜是因为我在 null 此处传递 testController.UpdateStates(null)。我确实尝试将 UpdateStates api 方法中的所有内容包装到 null 检查 update 参数,但这仍然产生相同的异常。如果需要更多代码,请告诉我,我将对此进行编辑 post.

应该等待主题,否则可以在主题完成预期行为之前做出断言

mock 还应配置为 return 传递的参数以模仿实际实现的预期行为

[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);
}

其他测试也应该做同样的事情

[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);
}

也就是说,应重构主题操作以遵循控制器的正确语法。

假设控制器派生自 ControllerBase 它可以访问操作结果的辅助方法。

[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);
}

问题是您正在检查 nullstate 之间的不相等。该函数已被调用,但为 null,而不是状态(相等性在引用上)。

试试这个:

        [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);
        }