值用于隔离地对控制器进行单元测试
本文关键字:单元测试 控制器 用于 隔离 | 更新日期: 2023-09-27 17:50:29
寻找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, Expect: BadRequest
- 给定: input4, 期望IHttpActionResult: PreconditionFailed
- …
这在概念上感觉非常干净,我的控制器和单元测试都与众所周知的IHttpActionResults交互(不是服务层或更低的概念)。
现在我将异常处理提升到一个全局处理程序,控制器单元测试现在抛出无数的服务或数据访问层异常。当然,我可以通过集成测试实现之前的功能,例如ExceptionHandler + controller。
问题:在这种设置中,单独对控制器进行单元测试的价值是什么?基线值似乎是使用ExceptionHandler + controller进行集成测试,以至少验证从各种输入返回的所有状态代码。
[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
。