Search code examples
c#unit-testing.net-coremstestfluentvalidation

Fluent TestValidate not raising validation errors for rules set on List with SetValidator


While using Fluent's Test Helpers TestValidate method to unit test my rules, it throws TestValidationException when List of object is null. The validator setup specifies the NotNull rule.

Validator looks like below

public class RequestValidator : AbstractValidator<Request>
{
    public RulebookRequestValidator()
    {
        RuleFor(x => x.Id).NotEmpty();
        RuleFor(x => x.Name).NotEmpty();
        RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull(); // Would like to validate this rule when EntryRequests is null.
    }
}

Child validator looks like this,

public class EntryRequestValidator : AbstractValidator<EntryRequest>
{
        public EntryRequestValidator()
        {
            RuleFor(x => x.EntryRequestId).NotEmpty();
            RuleForEach(x => x.Messages).NotNull().SetValidator(new MessagesValidator());
        }
 }

And in my unit test

[TestMethod]
public void Should_Have_Error_When_Object_Is_Empty()
{
    // arrange
    Request model = new () { EntryRequests = new () };
    var validator = new RequestValidator();

    // assert
    var result = validator.TestValidate(model);

    // act
    Assert.IsFalse(result.IsValid);
    result.ShouldHaveValidationErrorFor(x => x.Id)
            .WithErrorCode(NotEmptyValidatorErrorCode);
    result.ShouldHaveValidationErrorFor(x => x.Name)
            .WithErrorCode(NotEmptyValidatorErrorCode);
    result.ShouldHaveValidationErrorFor(x => x.EntryRequests); // throws ValidateTestException. 
 }

Is this the right approach to test child validators on a List in Unit test? Looking for a way to use TestValidate to unit test this rule.


Solution

  • Your validator works correctly, but has one tiny problem.

    Let's look at this rule:

    RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull();

    It basically says: Run a NotNull check (and execute EntryRequestValidator) against every element in the EntryRequest collection.

    It does not work because your collection is empty: EntryRequests = new (). It has no elements, so there is nothing to validate.

    Change it to:

    RuleFor(x => x.EntryRequests).NotEmpty(); // throws validation error when collection is null or empty
    RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull(); 
    

    With above rules you would get validation error when:

    • EntryRequests = null
    • EntryRequests = empty list
    • any element of this list is null

    plus all validations from nested validator