如何在动作过滤器中使用参数验证对 MVC 控制器进行单元测试?

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

我们有一个 MVC.NET Core Web API 应用程序,它使用操作过滤器来验证控制器方法的参数。

我们使用 FluentValidation 框架进行验证。在动作过滤器中,我们找到 IValidator<TModel> 其中 TModel 是控制器动作的参数,例如:

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

在过滤器的OnActionExecuting(ActionExecutingContext context)中,我们找到合适的验证器(IValidator<TModel>),验证参数(context.ActionArguments),如果验证失败,我们通过分配验证结果来短路进入 context.Result - 这意味着执行永远不会到达控制器。

基本原理类似于将 FluentValidation 连接到 MVC 的 ModelState 验证管道中,但我们需要一些额外的东西,所以我们手动完成。

我们想对控制器和验证器进行单元测试。问题在于对控制器进行单元测试。在测试设置中,我们实例化控制器并调用其方法之一。现在在生产环境中,参数将始终得到验证,并且仅当参数有效时才真正将其传递给控制器​​方法。但是当对控制器进行单元测试时,我们很容易传递无效参数并得到意想不到的行为。

原则上,有解决办法吗?或者我真的需要确保在测试方法中我将有效参数传递给控制器​​吗?

编辑:

我们还计划进行集成测试(很可能使用 .NET Core 的 TestServer)以确保管道正常工作。在此 post 中,我只想讨论有关从单元测试方法传递到控制器的无效参数的问题。

首先对验证器进行单元测试,以便明确定义哪些参数有效,哪些无效。

然后,正如您在问题中建议的那样,您可以只获取有效输入并专注于它们以对控制器进行单元测试。

最后,您可以使用有效参数和无效参数创建一些集成测试。

您需要在 ASP.NET Core 中编写集成测试 参见 link:https://docs.microsoft.com/en-us/aspnet/core/testing/integration-testing?view=aspnetcore-2.0

主要目标:您测试同一个网站 api 但它在您的测试中托管。

同意Nkosi评论说的,因为required属性不是controller直接使用的,而是框架modelbinder用来验证的(fluent validation也是基于此),所以单独调用controller方法可以' 单元测试此属性是否存在。它必须与框架进行集成测试。但是 asp.net 核心集成测试框架太重了,它可以测试整个流程,而不仅仅是模型绑定。我们需要一个模型绑定集成测试框架,运行 它可以断言模型状态是否有效,而不关心实际的控制器操作结果。也许我们可以自己写一个。