使用嵌套验证对复杂模型进行单元测试

nat*_*lez 3 .net tdd mocking fluentvalidation

我正在使用fluentvalidation进行模型验证.我有一个类,有几个嵌套类或类集合,每个类都有自己的IValidator.最初我正在做这样的事情来设置嵌套的验证器:

RuleFor(foo => foo.Header).SetValidator(new FooHeaderValidator());
Run Code Online (Sandbox Code Playgroud)

这非常有效.

当我开始实现更多的嵌套验证器时,我开始意识到我的单元测试对于顶级验证是多么脆弱.基本上,对子验证器的任何更改都可能导致意外行为并导致测试失败.显然这是由于我直接实例化了子验证器.我现在正在通过构造函数注入获取该依赖项.这让我嘲笑了FooHeaderValidator.

我现在测试失败了null reference,来自某个地方的例外来自流畅的验证.我只能假设某个地方有人要求我的模拟不提供.这是来自fluentvalidation的堆栈跟踪:

   at FluentValidation.Validators.ChildValidatorAdaptor.Validate(PropertyValidatorContext context)
   at FluentValidation.Validators.DelegatingValidator.Validate(PropertyValidatorContext context)
   at FluentValidation.Internal.PropertyRule.InvokePropertyValidator(ValidationContext context, IPropertyValidator validator, String propertyName)
   at FluentValidation.Internal.PropertyRule.<Validate>d__8.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList(IEnumerable`1 source)
   at FluentValidation.AbstractValidator`1.Validate(ValidationContext`1 context)
   at FluentValidation.AbstractValidator`1.Validate(T instance)
Run Code Online (Sandbox Code Playgroud)

有没有人遇到这个,知道我错过了什么?我是否因为嘲笑这些验证器而疯狂?

nat*_*lez 6

所以这实际上很简单.答案是你需要为Validate接受a 的覆盖设置你的模拟ValidationContext<T>.在RhinoMocks中,这看起来像:

public static IValidator<T> GetMockedNestedValidator<T>()
{
    var mockedValidator = MockRepository.GenerateMock<IValidator<T>>();
    abstractValidator.Stub(x => x.Validate(Arg<ValidationContext<T>>.Is.Anything)).Return(new ValidationResult());
    return mockedValidator;
}
Run Code Online (Sandbox Code Playgroud)

与Moq非常相似:

public static Mock<IValidator<T>> GetMockedNestedValidator<T>()
{
    var mockedValidator = new Mock<IValidator<T>>();
    abstractValidator.Setup(x => x.Validate(Arg<ValidationContext<T>>.Is.Anything)).Returns(new ValidationResult());
    return mockedValidator;
}
Run Code Online (Sandbox Code Playgroud)