如何改进FluentValidation的Must规则验证器及对应单元测试?
解决FluentValidation规则与单元测试不匹配的问题
你的问题核心在于:验证规则是绑定到整个对象上的,但测试却在检查单个CurrentValue属性的错误。FluentValidation会把对象级规则的错误标记为属于空字符串的属性名,而非CurrentValue,所以ShouldNotHaveValidationErrorFor(c => c.CurrentValue)自然会判断错误存在——因为错误根本不是关联到这个属性的。
这里有两种改进方向,推荐第一种:
方案一:调整验证规则,绑定到具体属性
把规则直接关联到CurrentValue属性,使用带两个参数的Must重载,这样既能访问整个模型的AllowedValues,又能让错误关联到CurrentValue属性,测试就能正常工作:
model.RuleFor(c => c.CurrentValue) .Must((modelInstance, currentValue) => string.IsNullOrEmpty(currentValue) || modelInstance.AllowedValues.Contains(currentValue)) .WithMessage("CurrentValue必须是允许值列表中的项,或者为空");
修改后,你的原有测试代码this.validator.ShouldNotHaveValidationErrorFor(c => c.CurrentValue, this.model)就能正确判断了——错误现在会被标记在CurrentValue属性上,测试可以精准检查这个属性的验证状态。
方案二:不修改验证器,调整测试逻辑
如果你不想改动验证规则,那就要针对整个对象的验证结果来做测试,而不是检查单个属性:
// 直接验证整个对象,检查是否有效 var validationResult = this.validator.Validate(this.model); validationResult.IsValid.Should().BeTrue(); // 或者更精准地检查是否存在对象级别的错误 validationResult.Errors.Any(e => string.IsNullOrEmpty(e.PropertyName)).Should().BeFalse();
因为原来的对象级规则产生的错误,其PropertyName是空字符串,所以可以通过检查是否存在这类错误来验证规则是否通过。
小建议
优先选方案一,因为把错误关联到具体属性不仅让测试更直观,也能在前端展示错误时精准定位到对应的输入框,提升用户体验。
内容的提问来源于stack exchange,提问作者Gabriel Castillo Prada
相关产品推荐
相关产品推荐

