模拟子验证器时 FluentValidation 抛出 NullReference 异常
NullReference exception throw by FluentValidation when mocking child validators
从简单的事情开始:
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"
堆栈跟踪:
at FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context) in
/home/jskinner/code/FluentValidation/src/FluentValidation/Validators/ChildValidatorAdaptor.cs:line 56
at FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context, IPropertyValidator validator, String propertyName) in
/home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 442
at FluentValidation.Internal.PropertyRule.d__65.MoveNext()
in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 282
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at FluentValidation.AbstractValidator1.Validate(ValidationContext
1 context) in
/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
at SubValidationTest.Program.Test_ParentValidator_WithMockedChildValidator()
是否需要在模拟的验证器上模拟其他东西才能使其正常工作?
我无法让此代码在 DotNetFiddle 上(完全)工作:(
从堆栈跟踪来看,它似乎在
上失败了
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();
}
从简单的事情开始:
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"
堆栈跟踪:
at FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context) in
/home/jskinner/code/FluentValidation/src/FluentValidation/Validators/ChildValidatorAdaptor.cs:line 56
at FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context, IPropertyValidator validator, String propertyName) in
/home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 442
at FluentValidation.Internal.PropertyRule.d__65.MoveNext()
in /home/jskinner/code/FluentValidation/src/FluentValidation/Internal/PropertyRule.cs:line 282
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at FluentValidation.AbstractValidator
1.Validate(ValidationContext
1 context) in/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
at SubValidationTest.Program.Test_ParentValidator_WithMockedChildValidator()
是否需要在模拟的验证器上模拟其他东西才能使其正常工作?
我无法让此代码在 DotNetFiddle 上(完全)工作:(
从堆栈跟踪来看,它似乎在
上失败了 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();
}