c# - 隔离单元测试 Controller 的值(value)

标签 c# asp.net asp.net-web-api asp.net-web-api2

在 asp.net web api 2 中寻找有关单元测试 Controller 的指南。我有一个标准的多层架构: Controller -> 服务层 -> 数据访问层。

服务层可能会抛出源自服务层的异常或来自数据访问层的异常 [1]。由于每个 Controller 方法中的异常处理逻辑非常简单:

public IHttpActionResult MyControllerAction()
{
    try
    {
    // do something and return IHttpActionResult
    }
    catch(Exception ex)
    {
    // map exceptions to specific IHttpActionResult with corresponding (status code and error (response body) formatting)
    return HandleException(ex);  
    }
}

我选择从每个 Controller 操作中提取 try/catch 和处理逻辑,并将其整合到一个地方。 其中一个 可以工作:{IHttpActionInvoker、ExceptionFilter 或 ExceptionHandler}。

不幸的是,因为异常处理逻辑现在在 Controller 之外,所以我的 Controller 单元测试不再隔离在 IHttpActionResult 级别。

以前我可以测试各种输入和预期输出,例如:

  • 给定: input1,期望 IHttpActionResult: OK
  • 给定: input2,期望 IHttpActionResult: NotFound
  • 给定: input3,期望 IHttpActionResult: BadRequest
  • 给定: input4,期望 IHttpActionResult: PreconditionFailed
  • ...

这在概念上感觉非常清晰,我的 Controller 和单元测试都与众所周知的 IHttpActionResults 交互(不是服务层或较低的概念)。

现在我将异常处理提升到全局处理程序, Controller 单元测试现在会抛出无数服务或数据访问层异常。当然,我可以通过集成测试实现我以前的目标,例如异常处理程序 + Controller 。

问题: 在这样的设置中,单独对 Controller 进行单元测试的值(value)是什么?似乎基准值是使用 ExceptionHandler + Controller 进行集成测试,以至少验证从各种输入返回的所有状态代码。

[1] 数据访问异常是通用的,并且与特定的数据访问实现无关。我没有看到将其包装在服务层异常中的值。

最佳答案

这并没有真正直接回答您的问题,但是异常处理集中化的替代方法是使用接受 lambda 或闭包的函数式方法:

(例如,在基本 Controller 或 Controller 助手上)

protected IHttpActionResult InvokeWithExceptionHandler(Func<IHttpActionResult> tryBlock)
{
    try
    {
        return tryBlock();
    }
    catch (Exception ex)
    {
        // map exceptions to specific IHttpActionResult ... etc
        return HandleException(ex);
    }   
}

这将允许您的 Controller 方法仅“编码” Controller 的快乐流程用例,从而获得相同的 DRY 异常处理行为,但仍允许与之前相同的单元可测试性:

    public IHttpActionResult DoSomething(MyEntity myModel)
    {
        return InvokeWithExceptionHandler(
            () =>
            {
                // ... Do controller things here
                return View("MyView", myModel);
            });
    }

我想如果有自定义的 catch 错误或 finally block 处理,您可以相应地重载 Invoker

这里的好处是您不需要重复异常处理单元测试场景,并且可以将单元测试集中在快乐案例 Controller 流程中的分支上。

关于c# - 隔离单元测试 Controller 的值(value),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22447756/

相关文章:

asp.net-mvc - 如何使用 Ninject 拦截来拦截所有 ASP.NET WebApi Controller 操作方法调用以进行日志记录?

asp.net-web-api - 为什么我们必须指定FromBody 和FromUri?

asp.net-web-api - 如何在 Web API OData 中发布具有导航关系的实体?

c# - 使用语句中的 MemoryStream - 我是否需要调用 close()

c# - 从当前日期(SSIS 脚本任务)加上 future N 周获取 YYYYWW 形式的周数和年份

asp.net - Tortoise SVN 操作后文件丢失 IIS_IUSRS 权限

asp.net - 如何使用 aspnet_regiis 选择/强制执行 AES 加密来加密 web.config 值?

c# - 导航管理器 NullReferenceException

c# - 使用 Windows 容器在 Docker Desktop 中运行 ASP.NET 时,传出 HTTP 请求超时

asp.net - 如何在 Chrome 开发者工具中查看发布到表单的数据大小?