Skip to content

Commit 81f0b2b

Browse files
committed
Add docs with guidance on mocking.
1 parent 80961b8 commit 81f0b2b

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

docs/testing.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,31 @@ There are also inverse methods available (`WithoutMessage`, `WithoutErrorCode`,
9090
## Asynchronous TestValidate
9191

9292
There is also an asynchronous `TestValidateAsync` method available which corresponds to the regular `ValidateAsync` method. Usage is similar, except the method returns an awaitable `Task` instead.
93+
94+
## Mocking
95+
96+
Validators are intended to be "black boxes" and we don't generally recommend mocking them. Within a test, the recommended appraoch is to supply a real validator instance with known bad data in order to trigger a validation error.
97+
98+
Mocking validators tends to require that you make assuptions about how the validators are built internally (both the rules contained within them, as well as FluentValidation's own internals). Mocking this behaviour leads to brittle tests that aren't upgrade-safe.
99+
100+
However if you find yourself in a situation where you absoloutely do need to mock a validator, then we suggest using `InlineValidator<T>` to create a stub implementation as this way you can take advantage of re-using FluentValidation's own internal logic for creating validation failures. We *strongly* recommend not using a mocking library. An example of using `InlineValidator` is shown below:
101+
102+
```csharp
103+
// Original validator that relies on an external service.
104+
// External service is used to check that the customer ID is not already used in the database.
105+
public class CustomerValidator : AbstractValidator<Customer>
106+
{
107+
public CustomerValidator(ICustomerRepository customerRepository)
108+
{
109+
RuleFor(x => x.Id)
110+
.Must(id => customerRepository.CheckIdNotInUse(id));
111+
}
112+
}
113+
114+
// If you needed to stub this failure in a unit/integration test,
115+
// you could do the following:
116+
var validator = new InlineValidator<Customer>();
117+
validator.RuleFor(x => x.Id).Must(id => false);
118+
119+
// This instance could then be passed into anywhere expecting an IValidator<Customer>
120+
```

0 commit comments

Comments
 (0)