在 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/