unit testing complex model with nested validation
.net, fluentvalidation, mocking, tdd
Solution
So this is actually straightforward. The answer is that you need to set up your mock for the `Validate` override that accepts a `ValidationContext<T>`. in RhinoMocks this looks like:
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;
}
With Moq its pretty similar:
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;
}
Problem
I'm using fluentvalidation to do model validation. I have a class with a several nested classes or collections of classes, each with their own IValidator. Initially I was doing something like this to set up the nested validators: ``` RuleFor(foo => foo.Header).SetValidator(new FooHeaderValidator()); ``` This works very well. As i began to implement more of the nested validators I began to realize how fragile my unit tests were for the top level validation. Basically any change to the child validators could cause unexpected behavior and cause tests to fail. Obviously this is due to my instantiating the child validators directly. I am now taking that dependency in via constructor injection. This is allowing me to mock the `FooHeaderValidator`. I now have tests failing with `null reference` exceptions coming from somewhere in fluent validation. I can only assume that somewhere down the line something is being asked for that my mock is not supplying. This is the stack trace from 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) ``` Has anyone run into this before and know what I'm missing? Am I being crazy for mocking these validators?