测试依赖其他属性的自定义验证器时抛出ArgumentNullException
看起来你在测试ConcatenatedDataValidator时遇到了两个棘手的问题:一是调用Validator.TryValidateProperty时抛出的ArgumentNullException,二是想避开模型上其他Required属性的干扰,只针对这个自定义验证器做测试。我来一步步帮你搞定:
一、先解决ArgumentNullException的根源
这个空指针异常是因为Validator.TryValidateProperty需要明确知道你要验证的是哪个属性——你之前创建的ValidationContext没有指定MemberName,所以方法找不到目标属性,直接报错了。
如果一定要用这个方法,你可以修改ValidationContext的创建代码,加上要验证的属性名:
context = new ValidationContext(model) { MemberName = nameof(TestedModel.ThisProperty) };
不过这只是解决了报错问题,还没处理“单独测试验证器”的需求,所以更优的方案是直接测试验证器本身。
二、单独测试自定义验证器,完全隔离其他验证规则
其实根本不需要通过Validator.TryValidateProperty或Validator.TryValidateObject这类会触发模型所有验证规则的方法。我们可以直接实例化ConcatenatedDataValidator,调用它的验证方法,这样就只会执行这个自定义验证器的逻辑,完全避开其他Required属性的影响。
修改后的测试代码示例
public class ConcatenatedDataValidatorTests { [Fact] public void IsValid_OtherValueIs00ThisValueIsNull_ReturnsValidationError() { // Arrange var validator = new ConcatenatedDataValidator(nameof(TestedModel.OtherProperty)); var model = new TestedModel { OtherProperty = "00", ThisProperty = null }; var context = new ValidationContext(model); // Act var validationResult = validator.GetValidationResult(model.ThisProperty, context); // Assert Assert.NotNull(validationResult); // 验证返回错误结果 Assert.False(string.IsNullOrEmpty(validationResult.ErrorMessage)); } [Fact] public void IsValid_OtherValueIs00ThisValueHasValue_ReturnsValid() { // Arrange var validator = new ConcatenatedDataValidator(nameof(TestedModel.OtherProperty)); var model = new TestedModel { OtherProperty = "00", ThisProperty = "test content" }; var context = new ValidationContext(model); // Act var validationResult = validator.GetValidationResult(model.ThisProperty, context); // Assert Assert.Null(validationResult); // 验证通过,返回null } }
额外提示:修复验证器里的潜在空指针问题
你的验证器代码里有个隐藏风险:如果property.GetValue返回null,调用chosenValue.Equals("00")会直接抛出NullReferenceException。建议先加个空值检查:
protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var property = validationContext.ObjectType.GetProperty(PropertyName); if(property == null) { return new ValidationResult($"{PropertyName} 属性不存在"); } var chosenValue = property.GetValue(validationContext.ObjectInstance, null); // 先检查chosenValue是否为null if (chosenValue == null) { return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName)); } if ((chosenValue.Equals("00") && (value == null || value.Equals(string.Empty))) || (chosenValue.Equals("01") && value != null)) { return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName)); } return null; }
这样调整后,你的测试不仅能顺利运行,还能精准测试自定义验证器的逻辑,完全不受其他属性的验证规则影响。
内容的提问来源于stack exchange,提问作者Lordzio

