Mattio
Mattio

Reputation: 2032

FluentValidation ShouldHaveValidationErrorFor with SetCollectionValidator

I'm using the FluentValidation library in an ASP.NET MVC project and, from a UI perspective, it's working as expected. Rule violations display the correct errors.

I have a parent class that has a validator and a collection property where that type has a validator. It's conceptually the same as described in the documentation.

I have a validator for a parent class...

public class MyFormValidator : AbstractValidator<MyFormViewModel>

...and I have a collection in MyFormViewModel...

public IList<ChildRow> ChildRowsAdded { get; set; }

...and I create a validator for the collection of that child class...

public class ChildRowValidator : AbstractValidator<ChildRow>

...and I use that child validator in the parent validator...

RuleFor(m => m.ChildRowsAdded).SetCollectionValidator(new ChildRowValidator());

While writing some unit tests, I noticed that ShouldHaveValidationErrorFor is not confirming the errors exist.

_validator.ShouldHaveValidationErrorFor(x => x.ChildRowsAdded, model);

That line in my test does not seem to see the errors. The test fails and the message says

FluentValidation.TestHelper.ValidationTestException : Expected a validation error for property AllergyRowsAdded.

If I manually .Validate() and look at the results, I see the error.

Has anyone run into this before? Is there an additional step I need to take to use ShouldHaveValidationErrorFor in this situation?

Upvotes: 8

Views: 10085

Answers (3)

Maruf
Maruf

Reputation: 456

Now, we can do it like that:

in child validator:

RuleForEach(request => request.ChildRowsAdded)
                .SetValidator(new ChildRowValidator())
                .When(request => request.ChildRowsAdded != null); // whatever your rule

And

 var result = _validator.TestValidate(model);
 result.ShouldHaveValidationErrorFor(x => x.ChildRowsAdded);

Upvotes: 1

Aaron Thomas
Aaron Thomas

Reputation: 5281

According to the docs, there is another way to test nested properties: a string name that represents the path to the nested property:

// You can also use a string name for properties that can't be easily represented with a lambda, eg:
result.ShouldHaveValidationErrorFor("Addresses[0].Line1");

Upvotes: 10

Electrionics
Electrionics

Reputation: 6782

Jookin is absolutely right in his comment:

ShouldHaveValidationErrorFor method doesn't designed to validate properties of properties, you can read about it here.

There are 2 solutions:

  1. Use ShouldHaveValidationErrorFor and test ChildRowValidator directly, like this: _childValidator.ShouldHaveValidationErrorFor(x => x.Name, childModel); // direct descendant property can be validated
  2. Avoid this helper method and use Assert class to check, if in ValidationResult object exists any error with name, that match your array item(s) property by regexp or simple string comparison.

Choose one, that much more meet your purposes.

Upvotes: 7

Related Questions