You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试依赖其他属性的自定义验证器时抛出ArgumentNullException

解决XUnit测试自定义验证器的两个问题:空指针异常与单独验证

看起来你在测试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:50:15