Business rules can be complicated and hence it becomes immensely important to automate the testing of those rules. The library, Fluent Validation, provides APIs to support the automated testing of the rules. In this article, we are going to have a look at how to unit test the validation logic written using fluent validation.
Before we begin !
I have been writing about the fluent validation library and below is the list of all the articles that I have published. I would recommend going through this list before coming to the unit testing part.
- Adding Fluent Validation in ASP .NET Core Web APIs
- ASP .NET Core API – Placeholders in Fluent Validation Messages
- ASP .NET Core API – Fluent Validations – Customizing Messages
- ASP .NET Core API – Fluent Validations – Collections
- ASP .NET Core API – Fluent Validators and Dependency Injection
- ASP .NET Core API – Fluent Validations – Cascade Behaviour
- Demo – Inheritance Validation using Fluent Validations
- ASP .NET Core API – Conditions in Fluent Validations
- ASP .NET Core API – Fluent Validations Based On Database Data
- ASP .NET Core API – Fluent Validation RuleSets
- ASP .NET Core API – Fluent Validation – Include Validators
We are going to use the same scenario that I discussed in one of the previous posts.
Let’s say we have an entity,
Student. It has properties –
Version, here Id is basically to uniquely identify the record. For calling AddStudent endpoint, id should be always zero, but for calling UpdateStudent endpoint, id should not be zero.
TheArticle about RuleSets
Versionproperty is supposed to be used in update endpoint. It is to avoid overwriting more recent version of the record. So, Version should be non-zero while calling update endpoint and it should be zero while calling Add endpoint.
Then in the previous article, we created 5 different validators for validating properties from
Student class. Then these validators were used to compose another 2 validators.
- StudentWithIdValidator, to check that
Idshould be greater than zero
- StudentWithoutIdValidator, to check that
Idshould be equal to zero
- StudentWithVersionValidator, to check that
Versionshould be greater than zero
- StudentWithoutVersionValidator, to check that
Versionshould be equal to zero
- StudentNameValidator, to apply validations to Name property
- AddStudentValidator, which contains validators combined for
AddStudentendpoint. This validator should be triggered from the add endpoint.
- UpdateStudentValidator, which contains validators combined together for
UpdateStudentendpoint. This validator should be triggered from the update endpoint.
The code snippet given below shows the code for these validators.
Create Unit Test Project
Let’s create a xUnit test project in the same solution where the API project containing above mentioned validators is located. Once the test project is created, add reference of the API project in the test project.
This is a namespace in the Fluent Validation library. This namespace provides a method
TestValidateAsync) method. This method should be used for testing purposes. This method returns a result,
TestValidationResult, on which we can perform assertions.
There are two important assertion methods:
These methods take expressions as input, where we can specify the property, for which the validation has failed (or passed).
There are two more methods. We can use
WithErrorMessage to verify that the error message also matches. And we want to make sure that there are no other errors apart from ones specified in the assertion, then we can also use the method,
A Sample Unit Test
Let’s create a class student validator and let’s add tests for two scenarios.
- When Id is non-zero, version is zero and name has more than 10 characters, then the
AddStudentValidatorvalidation should fail for Id property.
- When Id is non-zero, version is zero and name has more than 10 characters, then
UpdateStudentValidatorvalidation should fail for Version property.
As you can see in the code snippet given below, we have used assertion methods mentioned above to validate the validators. I hope this example should give fair idea about how the validators can be tested.
Points to Remember
If validators has asynchronous logic, then it is better to use
TestValidateAsync. Another thing is, when we are testing the types which are dependent on validators (e.g. controllers in our example), it is better to not mock the validator. We can mock the dependencies of validator if they have any.
I hope you find this information helpful. Let me know your thoughts.