Search code examples
c#unit-testingfluentvalidationasp.net-mvc-filters

How to unit test MVC controller with argument validation in action filter?


We have an MVC.NET Core Web API app which uses an action filter to validate the controller's methods' arguments.

For validation we use FluentValidation framework. In the action filter, we find the IValidator<TModel> where TModel is the argument of the controller action, eg:

public async Task<IActionResult> Post([FromBody] TModel model)
{
}

In the filter's OnActionExecuting(ActionExecutingContext context) we find the proper validator (IValidator<TModel>), validate the arguments (context.ActionArguments) and if validation fails, we short-circuit by assigning the validation result into the context.Result - which means the execution never reaches the controller.

Basic principle is similar to hooking up FluentValidation into the MVC's ModelState validation pipeline but we need some extra things so we're doing it manually.

We would like to unit test both the controller and the validator. The problem is with unit testing the controller. In the test setup we instantiate the controller and call one of its methods. Now in production environment, the arguments will always get validated and actually make it to the controller method only if the arguments are valid. But when unit testing the controller, we can easily pass invalid arguments and get unexpected behaviour.

In principal, is there a way around this? Or do I actually need to make sure that in the test method I pass valid arguments to the controller?

EDIT:

We are also planning on integration testing (most likely using .NET Core's TestServer) to make sure the pipeline is working. In this post, I would like to discuss only the issue around invalid arguments passed from unit test methods to the controller.


Solution

  • You need to write Integration tests in ASP.NET Core see link: https://learn.microsoft.com/en-us/aspnet/core/testing/integration-testing?view=aspnetcore-2.0

    The main goal: you test the same web api but it hosts in your tests.