背景和目的
为了提高系统稳定性,通常我们有两方面的计划:- 黑盒测试:自动化测试,以接口来主体,通过控制入参的形式,检验出参,来模拟用户在线上的实际业务;(可以覆盖绝大部分的业务)
- 白盒测试:单元测试,以关键逻辑方法为主体,通过控制入参的形式,检验数据变化,站在开发的角度上来模拟实际调用(可以覆盖复杂方法,在黑盒测试中,很难测到的的数据变化)
什么时候需要写单元测试
- 项目(必写) 开发方案阶段,应该整理出所有的核心业务点,针对核心业务点来规划需要写的单元测试;在实际开发的前中期,(比如前期把基础数据的建立后)开始编写核心方法,然后设计单元测试的场景,编写单元测试;
- 需求包(选写) 需求包中有复杂逻辑时,大家都觉得容易出错、不好测;
- 线上问题(选写) 复杂逻辑,可能该逻辑已经有单元测试了,但是线上问题完美避开了所有场景,单元测试中补充该场景以及类似场景; 复杂逻辑,可能是旧代码 或者 之前认为不复杂所以不必测试,补充单元测试;
哪些方法需要写单元测试
核心复杂逻辑,黑盒测试上难以测到的,同上;如何覆盖尽可能多的场景
-
常规场景(happy pass)
- 业务1
- 业务2
- 业务3
- 边界场景 :徘徊在边界上的入参或数据条件,依旧能得到相应的结果;
- 异常场景 :超出边界之外的入参或数据条件,判断异常达到预期;
如何写单元测试
-
优化方法,明确方法的含义; 如果方法已存在在先,想对它写单元测试,首先得确保该方法有以下特点:
- 语义化:单独看这个方法,有明确的含义,功能单一;
- 入参出参明确;
- 去掉不必要测试的代码范围:1)入库相关,比如sql、redis、mq、es;2)远端调用;
-
写单元测试 一般的代码步骤:
- 声明已知数据;
模拟无需测试的接口方法;- 调同需要测试的接口方法;
- 检验数据变化是否符合预期;
与开发和发布流程闭环
1、开发 开发过程中随时都可以在IDE跑单元测试,右键项目、类、测试方式都可以跑单元测试
2、发布 Jenkins中可以集成单元测试环节,当我们去发布的时候首先会去跑单元测试项目,只有当单元测试都通过时,才会继续发布;当单元测试未通过,可以通知IM消息通知群里的链接点进去,查看失败的用例,修复代码并重新发布;
如何搭建单元测试项目
1、选择合适的单元测试框架
https://zhuanlan.zhihu.com/p/644833761
推荐使用Xunit,原因无非是支持的扩展包比较多,功能全,使用起来比较方便;
2、注入实例
注入实例的原因在于,已有项目的接口通常在构造函数里有大量的注入,如果我们要实例化该接口的话,就要mock它所依赖的所有注入接口,如果构造函数里有几十个依赖的接口,那想测试该接口将会变得异常困难,
所以我们主要需要解决的问题就是注入问题,让我们写单元测试的时候跟写一半业务代码一样简单;
大体的注入思想是:
① 自定义接口(比如IxxxService,IxxxRepo)复用原有项目的注入,最好是提取出来同一个文件,给api project和单元测试 project能复用,避免两边改;
②数据库ef上下文、redis、mq、es、cap等等中间件,坚持一个原因:能进内存的就进内存;
这些组件都是支持注册进内存的,网上查一下很简单就能配置;
进内存的意义在于,虽然我们不建议测这些中间件相关的代码,但是万一无意执行到了不会无端报错,另外如果真的要测到经过这些中间件的代码时,也是可以支持的,因为数据放在内存里也是可以承载的;
③原生sql如何支持
如果万不得已,要测到原生sql时,官方只支持sqlite,改成sqlite注册为本地文件就可以了;
但是有一个问题,我们代码里可能都没写库名以及schma,当我们有多个dbcontext,而且dataset还交互存在时,就会不可避免的报错了,这里就没办法不动源代码了,目前看来用sqlsugar来改造源代码,避免使用dbcontext才能根本上解决吧;
3、单元测试startup
using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
xunit 单元测试项目引用这些就可以跟api项目一样配置startup文件了,ConfigureServices 、Configure、ConfigureHost都能一样写了;
如果想使用配置文件的话,使用ConfigureHost就可以搞定了;为啥用使用不同配置,比如本地和线上的数据库连接不是同一个,等等各种原因都需要线上线下使用不同配置;
4、为啥很少用mock
就像第2步注入实例里说的,实例化一个接口,需要mock它依赖的所有或部分接口,使用起来非常麻烦,而且我们说单元测试的目的是测试核心方法,并不是去像白盒测试(自动化测试)一样去测试整个流程,
所以我们通常测的方法都是纯逻辑,方法功能单一,入参和出参明确,所以我们想要跟写业务代码一样简单来写单元测试,测试那些复杂逻辑是否有漏洞;
标签:core,场景,代码,单元测试,接口,测试,net,方法 From: https://www.cnblogs.com/willardzmh/p/17934594.html