.NET Core 2中Mock FluentValidation的ValidationResult.IsValid测试卡住问题
解决控制器Mock FluentValidation验证器时测试无限挂起的问题
你的测试无限运行的核心问题有两个,咱们一个个拆解:
1. 手动创建的未启动Task导致await无限等待
你在Mock ValidateAsync方法时,用new Task<ValidationResult>(() => validationResultMock.Object)返回任务,但这种方式创建的Task处于Created状态——它根本没开始执行!当控制器里执行await _authenticateRequestValidator.ValidateAsync(req)时,代码会一直等待这个任务完成,但它永远不会运行,自然就无限挂起了。
正确的做法是返回一个已完成的Task,要么用Task.FromResult,要么直接用Moq提供的ReturnsAsync方法(更简洁,推荐)。
2. 测试逻辑与预期不符
你的测试目标是验证“用户名验证失败时返回400”,但你把ValidationResult.IsValidMock成了true——这会让控制器认为验证通过,根本不会进入BadRequest分支,就算解决了Task的问题,这个测试也会失败。
修正后的测试代码
把你的Mock部分改成这样,就能同时解决两个问题:
[Fact] public async Task Authenticate_Returns400_WhenUsernameValidationFails() { // Arrange var request = Fixture.Create<AuthenticateRequest>(); // 模拟验证失败的结果,符合测试场景预期 var validationResultMock = new Mock<ValidationResult>(); validationResultMock .SetupGet(x => x.IsValid) .Returns(false); // 用ReturnsAsync返回已完成的任务,避免手动创建未启动的Task authenticateRequestValidatorMock .Setup(x => x.ValidateAsync(It.Is<AuthenticateRequest>(v => v == request), default(CancellationToken))) .ReturnsAsync(validationResultMock.Object); var controller = new SecurityController(authenticateRequestValidatorMock.Object); // Act var result = await controller.AuthenticateAsync(request); // Assert var badRequestResult = Assert.IsType<BadRequestResult>(result); // 注意你的控制器返回的是BadRequest(),而非BadRequestObjectResult Assert.Equal(400, badRequestResult.StatusCode); }
额外优化建议
- 如果你不需要验证
ValidationResult的其他属性,甚至可以不用MockValidationResult,直接返回一个真实的无效结果:authenticateRequestValidatorMock .Setup(x => x.ValidateAsync(It.IsAny<AuthenticateRequest>(), default)) .ReturnsAsync(new ValidationResult(new List<ValidationFailure> { new ValidationFailure("Username", "Username is required") })); - 用
It.IsAny<AuthenticateRequest>()代替It.Is<AuthenticateRequest>(v => v == request)会让测试更灵活,除非你需要严格匹配请求实例。
内容的提问来源于stack exchange,提问作者Spikeh
相关产品推荐
相关产品推荐

