MediatR架构下薄控制器与简易处理程序的测试必要性咨询
薄封装控制器的测试必要性判断
- 你的核心判断是对的:这类逐控制器写单测的做法,本质上就是在测试MediatR本身的功能、测试BaseController里已经测过的
HttpResponse方法,确实没有实际价值。 - 真正需要兜底的风险,根本不需要写逐控制器的单测:
- 路由写错:比如把
[Route("filter")]写成[Route("fliter")],这种写个启动时的路由表扫描,把所有控制器路由打出来和预期配置对一遍就行,不用每个控制器单独测。 - 入参绑定出问题:比如本来要接收
[FromBody]不小心写成[FromQuery],这种用一次端到端的集成测试请求扫一遍所有路由的入参绑定规则就能兜住。 - 依赖注册漏配:比如某个Command没有对应的Handler,运行时MediatR会抛异常,这种在程序启动的时候做一次依赖注入容器的校验就能发现,根本不用单测。
- 路由写错:比如把
- 完全不建议做的操作:为了凑测试覆盖率,给每个薄控制器写“mock Mediator.Send,断言它被调用了一次,参数是传入的data,断言HttpResponse被调用了一次,参数是Mediator的返回值”这种测试。这种测试除了让覆盖率数字好看,没有任何业务价值,后续哪怕你只是把方法名改了,都要同步改一堆测试,纯纯的技术债。
纯转发型MediatR Handler的测试必要性判断
- 先给结论:这类Handler的测试价值比薄控制器高一点点,但也远达不到要写全量mock测试的程度。
- 你说的“测试这类Handler本质是校验mock对象”的判断,针对那种“透传返回值”的测试是完全成立的:如果Handler里没有任何逻辑,直接调用下游服务方法返回结果,那测试它是不是把服务的返回值原样返回,确实没有任何意义——这个行为本来就是代码最直白的表达,写测试除了拖慢运行速度没有任何收益。
- 这类Handler唯一真实的风险,是多参数传参错配:看你贴的代码,
FilterAsync方法的调用如下:
这个方法有12个入参,其中还有一个硬编码的return await _context.FilterAsync(request.DateFrom, request.DateTo, request.Versions, request.Areas, request.Domains, request.Actions, request.Users, request.Agents, request.Responses, null, request.Duration, request.EntityId);null值,这种情况下极容易出现参数顺序写错的问题,比如把request.Users传到Agents的位置、把request.Duration传到EntityId的位置。这种错误代码评审的时候人眼很容易漏,而且下游服务已经充分测试过了,根本不会抛异常,只会返回错误的业务数据,等用户反馈的时候已经晚了。 - 针对这个风险,你完全不需要写复杂的全链路测试,只要写一个超简单的测试:mock掉
IAnalyticModuleStore的FilterAsync方法,捕获传入的所有参数,断言这些参数和Command里的对应属性值完全匹配就行。这种测试写起来5分钟,就能把最容易出问题的点兜住,剩下的透传逻辑根本不用测。 - 同样没必要做的事:给这类Handler写“传入Command→触发Handler调用→断言返回值和mock的服务返回值一致”的测试,这种就是你说的只校验了伪造对象的冗余测试,纯浪费时间。
适合这类架构的测试优先级建议
- 测试资源优先倾斜到真的有业务逻辑的代码:比如带权限判断、数据校验、规则计算的MediatR Handler、领域服务,这类代码出问题是真的会造成业务损失的。
- 薄封装、纯透传的代码,优先用静态分析、启动时依赖校验、基础集成扫描这类低成本的自动化方案兜底,不要花时间写逐行的单元测试。
- 永远不要为了满足测试覆盖率的KPI写无意义的测试:那种“mock所有依赖,断言依赖方法被调用”的测试,是后期维护成本最高的测试债,没有之一。
内容的提问来源于stack exchange,提问作者rbasniak
相关产品推荐
相关产品推荐

