Unit testing FluentValidation rules for classes with sub/child classes

Vdex picture Vdex · Dec 17, 2012 · Viewed 11.1k times · Source

Is it possible to write unit tests for fluentvalidation classes when the object we are validating has child classes that are also being validated.

As an example: My class looks like this

public class TestModel
{

    public class SubData
    {
        public int SubDataVal { get; set; }
    }

    public int ParentVal { get; set; }
    public SubData Sub { get; set; }

}

My validation logic looks like this:

public class TestModelValidator : AbstractValidator<TestModel>
{
    public TestModelValidator()
    {
        RuleFor(o => o.ParentVal).GreaterThan(0);
        RuleFor(o => o.Sub.SubDataVal).GreaterThan(0);
    }
}

And when I write the following unit test

    [Test]
    public void Should_have_error_when_val_is_zero()
    {
        validator = new TestModelValidator();
        validator.ShouldHaveValidationErrorFor(model => model.ParentVal, 0);
    }

I get a "System.NullReferenceException : Object reference not set to an instance of an object." exception from FluentValidation.TestHelper.ValidatorTester`2.ValidateError(T instanceToValidate)

(if I remove the RuleFor(o => o.Sub.SubDataVal).GreaterThan(0); line, then it works!)

Similarly if I try and unit test the actual child class with:

    [Test]
    public void Should_have_error_when_sub_dataVal_is_zero()
    {
        validator = new TestModelValidator();
        validator.ShouldHaveValidationErrorFor(model => model.Sub.SubDataVal, 0);
    }

I get a "System.Reflection.TargetException : Object does not match target type." from FluentValidation.TestHelper.ValidatorTester`2.ValidateError(T instanceToValidate)

Answer

MarkG picture MarkG · Dec 23, 2012

You can unit test models and child models but you will need to change your validation class to use a separate validator class which just validates the child model:

public class TestModelValidator : AbstractValidator<TestModel>
{
    public TestModelValidator()
    {
        RuleFor(o => o.ParentVal).GreaterThan(0);
        RuleFor(o => o.Sub).SetValidator(new SubDataValidator());
    }
}

public class SubDataValidator : AbstractValidator<SubData>
{
    public SubDataValidator()
    {
        RuleFor(o => o.SubDataVal).GreaterThan(0);
    }
}

You can then write your unit tests to test each validator or both together.