【问题标题】:value in unit testing controllers in isolation独立单元测试控制器的价值
【发布时间】:2014-04-22 06:26:03
【问题描述】:

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

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

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);  
    }
}

我选择将 try/catch 和处理逻辑从每个控制器操作中提取出来,并将其整合到一个地方。 以下一个会起作用:{IHttpActionInvoker、ExceptionFilter 或 ExceptionHandler}。

不幸的是,由于异常处理逻辑现在不在控制器之外,我的控制器单元测试不再隔离在 IHttpActionResult 级别。

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

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

这在概念上感觉非常干净,我的控制器和单元测试都与众所周知的 IHttpActionResults 交互(不是服务层或更低的概念)。

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

问题: 在这样的设置中,单独对控制器进行单元测试的价值是什么?似乎基线值是与 ExceptionHandler + 控制器进行集成测试,以至少验证从各种输入返回的所有状态代码。

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

【问题讨论】:

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


    【解决方案1】:

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

    (例如在基本控制器或控制器助手上)

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2010-11-11
      • 2020-08-12
      • 2017-06-26
      • 2011-12-01
      相关资源
      最近更新 更多