.net core 单元测试项目搭建

背景和目的

为了提高系统稳定性,通常我们有两方面的计划:
  • 黑盒测试:自动化测试以接口来主体,通过控制入参的形式,检验出参,来模拟用户在线上的实际业务;(可以覆盖绝大部分的业务)
  • 白盒测试:单元测试以关键逻辑方法为主体,通过控制入参的形式,检验数据变化,站在开发的角度上来模拟实际调用(可以覆盖复杂方法,在黑盒测试中,很难测到的的数据变化)
ps:本篇主要介绍白盒测试,也就是代码层次的单元测试;

什么时候需要写单元测试

  1. 项目(必写) 开发方案阶段,应该整理出所有的核心业务点,针对核心业务点来规划需要写的单元测试;在实际开发的前中期,(比如前期把基础数据的建立后)开始编写核心方法,然后设计单元测试的场景,编写单元测试;
  2. 需求包(选写) 需求包中有复杂逻辑时,大家都觉得容易出错、不好测;
  3. 线上问题(选写) 复杂逻辑,可能该逻辑已经有单元测试了,但是线上问题完美避开了所有场景,单元测试中补充该场景以及类似场景; 复杂逻辑,可能是旧代码 或者 之前认为不复杂所以不必测试,补充单元测试;

哪些方法需要写单元测试

核心复杂逻辑,黑盒测试上难以测到的,同上;

如何覆盖尽可能多的场景

  1. 常规场景(happy pass)
    1. 业务1
    2. 业务2
    3. 业务3
  2. 边界场景 :徘徊在边界上的入参或数据条件,依旧能得到相应的结果;
  3. 异常场景 :超出边界之外的入参或数据条件,判断异常达到预期;
总体上来讲,可以分为常规、边界、异常三种套路,每种套路依据实际业务场景可以验证多种结果,毕竟实际业务可能不止一种常规结果;
 

如何写单元测试

  1. 优化方法,明确方法的含义; 如果方法已存在在先,想对它写单元测试,首先得确保该方法有以下特点:
    1. 语义化:单独看这个方法,有明确的含义,功能单一;
    2. 入参出参明确;
    3. 去掉不必要测试的代码范围:1)入库相关,比如sql、redis、mq、es;2)远端调用;
  2. 写单元测试 一般的代码步骤:
    1. 声明已知数据;
    2. 模拟无需测试的接口方法;
    3. 调同需要测试的接口方法;
    4. 检验数据变化是否符合预期;
模拟接口会带来巨量的工作量,而且大部分工作量是低效且无需测试的,所以在写代码测试的时候,首先要优化方法,然后推荐用注入的方式来测试,避开需要模拟非必要接口方法的情况;

与开发和发布流程闭环

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它依赖的所有或部分接口,使用起来非常麻烦,而且我们说单元测试的目的是测试核心方法,并不是去像白盒测试(自动化测试)一样去测试整个流程,

所以我们通常测的方法都是纯逻辑,方法功能单一,入参和出参明确,所以我们想要跟写业务代码一样简单来写单元测试,测试那些复杂逻辑是否有漏洞;

 

 

 

 

 

 
 
posted @ 2023-12-29 15:58  willardzmh  阅读(93)  评论(0编辑  收藏  举报