代码之家  ›  专栏  ›  技术社区  ›  Erik Philips Gabriel Costa

模拟子验证程序时FluentValidation引发的NullReference异常

  •  0
  • Erik Philips Gabriel Costa  · 技术社区  · 5 年前

    从简单的事情开始:

    public interface IChild
    {
      string Value { get; }
    }
    
    public class ChildValidator : AbstractValidator<IChild>
    {
      public ChildValidator()
      {
        RuleFor(c => c.Value)
          .NotEmpty()
          .NotEmpty()
          .WithMessage("Friendly Error Message");
      }
    }
    

    然后测试它:

    static void Test_ChildValidator()
    {
      var child = Substitute.For<IChild>();
      var validator = new ChildValidator();
    
      child.Value.Returns(null as string);
      validator.Validate(child).IsValid.Should().BeFalse();
    
      child.Value.Returns("");
      validator.Validate(child).IsValid.Should().BeFalse();
    
      child.Value.Returns("a");
      validator.Validate(child).IsValid.Should().BeTrue();
    }
    

    没有例外 .

    创建父对象和验证程序:

    public interface IParent
    {
      IChild Child { get; }
    }
    
    public class ParentValidator : AbstractValidator<IParent>
    {
      public ParentValidator(IValidator<IChild> childValidator)
      {
        When(p => p.Child != null, () => {
          RuleFor(p => p.Child)
            .SetValidator(childValidator);
        });
      }
    }
    

    然后用真正的子验证程序测试:

    static void Test_ParentValidator_WithRealChildValidator()
    {
      var child = Substitute.For<IChild>();
      var childValidator = new ChildValidator();
    
      var parent = Substitute.For<IParent>();
      var validator = new ParentValidator(childValidator);
    
      parent.Child.Returns(null as IChild);
      validator.Validate(parent).IsValid.Should().BeTrue();
    
      parent.Child.Returns(child);
      validator.Validate(parent).IsValid.Should().BeFalse();
    
      child.Value.Returns("a");
      validator.Validate(parent).IsValid.Should().BeTrue();
    }
    

    没有例外。

    现在我尝试模拟子验证器(最终我只想确保当子对象为null或不为null时,子验证器 Validate

    static void Test_ParentValidator_WithMockedChildValidator()
    {
      var child = Substitute.For<IChild>();
      var childValidator = Substitute.For<IValidator<IChild>>();
    
      var parent = Substitute.For<IParent>();
      var validator = new ParentValidator(childValidator);
    
      parent.Child.Returns(null as IChild);
      validator.Validate(parent).IsValid.Should().BeTrue();
    
      parent.Child.Returns(child);
    
      childValidator.Validate(Arg.Any<IChild>())
        .Returns(
          new ValidationResult(
            new List<ValidationFailure> { new ValidationFailure("property", "message") }));
      validator.Validate(parent).IsValid.Should().BeFalse();
    
      childValidator.Validate(Arg.Any<IChild>())
        .Returns(new ValidationResult());
      validator.Validate(parent).IsValid.Should().BeTrue();
    }
    

    抛出 NullReferenceException

    来源:“FluentValidation”

    在FluentValidation.Validators.ChildValidatorAdapter.Validate(PropertyValidatorContext上下文)中

    /home/jskinner/code/FluentValidation/src/FluentValidation/Validators/ChildValidatorAdaptor.cs:第56行

    在FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context,IPropertyValidator validator,String propertyName)中

    /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:第442行

    在FluentValidation.Internal.PropertyRule.d\uu 65.MoveNext()

    位于System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()

    位于System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()

    在FluentValidation.AbstractValidator 1.Validate(ValidationContext 1)在

    在/home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs中的FluentValidation.AbstractValidator`1.Validate(T instance):第83行

    我还需要在模拟的验证器上模拟其他东西来正确地工作吗?

    pastebin - full source code

    我无法在DotNetFiddle上运行此代码:(

    0 回复  |  直到 5 年前
        1
  •  1
  •   Nkosi    5 年前

    从堆栈跟踪来看,它似乎失败了

     FluentValidation.AbstractValidator1.Validate(ValidationContext1 context)
    

    这应该和预期的一样

    [TestMethod]
    public void Test_ParentValidator_WithMockedChildValidator() {
        var child = Substitute.For<IChild>();
        var childValidator = Substitute.For<IValidator<IChild>>();
        var parent = Substitute.For<IParent>();
        var validator = new ParentValidator(childValidator);
        parent.Child.Returns(null as IChild);
    
        validator.Validate(parent).IsValid.Should().BeTrue();
    
        parent.Child.Returns(child);
        var failedResult = new ValidationResult(new List<ValidationFailure> { new ValidationFailure("property", "message") });
        childValidator.Validate(Arg.Any<ValidationContext>()).Returns(failedResult);
    
        validator.Validate(parent).IsValid.Should().BeFalse();
    
        var validResult = new ValidationResult();
        childValidator.Validate(Arg.Any<ValidationContext>()).Returns(validResult);
    
        validator.Validate(parent).IsValid.Should().BeTrue();
    }