简体   繁体   English

模拟子验证器时 FluentValidation 抛出 NullReference 异常

[英]NullReference exception throw by FluentValidation when mocking child validators

Starting with something simple:从简单的事情开始:

public interface IChild
{
  string Value { get; }
}

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

And then testing it:然后测试一下:

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();
}

No Exceptions .没有例外

Create a parent object and validator:创建一个父对象和验证器:

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);
    });
  }
}

Then test that with a real child validator:然后用一个真正的子验证器测试它:

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();
}

No Exceptions.没有例外。

Now I tried to Mock the Child Validator (Eventually I just want to make sure that when the Child object is null or is not null, the child validator Validate method is or isn't called).现在我尝试模拟子验证器(最终我只想确保当 Child 对象为 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();
}

Throws a NullReferenceException抛出NullReferenceException

Source: "FluentValidation"来源:“FluentValidation”

StackTrace:堆栈跟踪:

at FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context) in在 FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context) 中

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

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

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

at FluentValidation.Internal.PropertyRule.d__65.MoveNext()在 FluentValidation.Internal.PropertyRule.d__65.MoveNext()

in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 282在 /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 282

at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()在 System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()

at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()在 System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()

at FluentValidation.AbstractValidator 1.Validate(ValidationContext 1 context) in在 FluentValidation.AbstractValidator 1.Validate(ValidationContext 1 context) 中

/home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 115 /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 115

at FluentValidation.AbstractValidator`1.Validate(T instance) in /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 83在 FluentValidation.AbstractValidator`1.Validate(T instance) in /home/jskinner/code/FluentValidation/src/FluentValidation/AbstractValidator.cs:line 83

at SubValidationTest.Program.Test_ParentValidator_WithMockedChildValidator()在 SubValidationTest.Program.Test_ParentValidator_WithMockedChildValidator()

Is there something else I need to mock on the mocked validator to make this work correctly?我还需要在模拟验证器上模拟其他东西才能使其正常工作吗?

pastebin - full source code pastebin - 完整的源代码

I was not able to get this code working (at all) on DotNetFiddle :(我无法让这段代码在 DotNetFiddle 上工作(根本):(

From the stack trace it looks like it fails on从堆栈跟踪看来它失败了

 FluentValidation.AbstractValidator1.Validate(ValidationContext1 context)

which was not one of the member configured on the mock.这不是模拟上配置的成员之一。

This should behave as expected这应该按预期运行

[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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM