Mockito提升单元测试覆盖率

news/2024/11/14 19:32:53/文章来源:https://www.cnblogs.com/hotMemo/p/18341139
简单实战
    1、准备工作
   从gitee下载一个例子工程,下面会在这个工程下补充测试用例

        

  选择的是 Ruoyi的后台代码,gitclone之后,添加几个依赖,因为习惯用

@RunWith(MockitoJUnitRunner.class) 的方式,就添加了下面的两个依赖

 

 第一个Mockito是这篇文章的主题,第二个junit4能让我使用

@RunWith(MockitoJUnitRunner.class)的方式
也能使用Springboot自带的test,但对我来说有亿点点细节,偏离主题。

  

2、编写基本架子

 

 @InjectMock标注测试哪个类,比如这里是测试 TokenController类,因为TokenController中的方法要用到StringUtils的静态方法,在每个测试方法之前mock下静态的工具类,需要在每次测试之后close一下,不然接下来的@Test方法会报错。我讲究是能一下子通过一个Controller方法就把之后的代码行给覆盖到(当然大佬听到这话至少有三句话要说...),所以SysLoginService的类我使用@Spy,@Spy能执行被注解类的方法里。TokenService是二方包里的,我用@Mock注解。

3、业务代码的逻辑

以TokenController 的logout方法为例

 接收的参数是HttpServletRequest,这个直接Mock,无需new,不然要实现许多没用的方法;首先是静态类 SecurityUtils.getToken,第二行是StringUtils.isNotEmpy,要让它走进里面,这行必须为true,或者SecurityUtils.getToken设置return一个值;之后是jwtUtils.getUserName(token),这行必须返回个userName,供下面的sysLoginService.logout使用,然后是AuthUtil.logoutByToken,没有返回值,直接doNothing()就行,接下来就是sysLoginService.logout,SysLoginService我用的@Spy,目的就是能从Conroller类覆盖到Service类,还需要看下它里面的逻辑,之后是R.ok()无需赘言。

 SysLoginService 里的logout只有一行逻辑,使用的类RecordLogService,它也在当前项目中,我也要让它的recordLogininfor方法覆盖到。如果在运行单元测试的时候能运行到RecordLogService呢,这个类是跟SysLoginService关联的,在这个测试方法中,没有直接跟TokenController直接关联,所以在@Spy RecordLogService后,还得使用,如下:

 ReflectUtils.setFieldValue(sysLoginService, "recordLogService", sysRecordLogService); 通过反射将 sysRecordLogService注入到sysLoginService中

看下 sysRecordLogService.recordLogininfor的逻辑

 没有什么特殊,remoteLogService是二方包里的方法,只需要将它的Mock对象通过ReflectionUtils set到sysRecordLogService中。

 

4、单元测试代码

 完整代码:

@RunWith(MockitoJUnitRunner.class)
public class TokenControllerTest {
  // MockedStatic 是业务逻辑中要用的的工具类,需要mocked一下
MockedStatic<SecurityUtils> mockedStaticSecurityUtils;
MockedStatic<JwtUtils> mockedStaticJwtUtils;
MockedStatic<AuthUtil> mockedStaticAuthUtil;
  // 这个是上面AuthUtil要依赖的,static new 了一下,new的过程中用到了SpringUtils.getBean的方法,这个也需要mock,并且mock getBean这个方法
MockedStatic<SpringUtils> mockedStaticSpringUtils;
@Spy
private SysRecordLogService sysRecordLogService;
@Spy
private SysLoginService sysLoginService;
@Mock
private RemoteLogService remoteLogService;
@InjectMocks
private TokenController tokenController;
@Before // 每个用@Test标注的方法之前执行
public void setup() {
mockedStaticJwtUtils = Mockito.mockStatic(JwtUtils.class);
mockedStaticSecurityUtils = Mockito.mockStatic(SecurityUtils.class);
mockedStaticSpringUtils = Mockito.mockStatic(SpringUtils.class);
mockedStaticSpringUtils.when(() -> SpringUtils.getBean(eq(Class.class))).thenReturn(null);
mockedStaticAuthUtil = Mockito.mockStatic(AuthUtil.class);
ReflectUtils.setFieldValue(sysLoginService, "recordLogService", sysRecordLogService);
ReflectUtils.setFieldValue(sysRecordLogService, "remoteLogService", remoteLogService);
}
@After // 每个用@Test标注的方法之后执行
public void after() {
     // 每次@Test的方法执行后都必须close一下,不然之后的@Test方法报错
mockedStaticJwtUtils.close();
mockedStaticSecurityUtils.close();
mockedStaticAuthUtil.close();
mockedStaticSpringUtils.close();
}
@Test
public void should_logout_ok_when_username_and_password_ok() {
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
mockedStaticSecurityUtils.when(() -> SecurityUtils.getToken(request)).thenReturn("111");
mockedStaticJwtUtils.when(() -> JwtUtils.getUserName("111")).thenReturn("111");
tokenController.logout(request);
verify(remoteLogService).saveLogininfor(Mockito.any(), eq(SecurityConstants.INNER));
}
}

 5、SHOWTIME

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/801595.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql安装(windows-mysql-8.1.0-winx64.zip安装)

1、官网下载,解压缩2、配置环境变量3、新增my.ini文件,根据电脑环境修改配置 # 设置mysql的安装目录 basedir # 设置mysql数据库的数据的存放目录 datadir my.ini文件内容如下: [mysqld]# 设置3306端口port=3306# 设置mysql的安装目录basedir=D:\kaifa\mysql-8.1.0-winx64# …

【游记】CSP-S2024游记

寄。CSP-S2024 游记展开目录 目录CSP-S2024 游记初赛9.21 上午9.21 下午初赛 9.21 上午 关于为什么从比赛当天开始,原因是我记性太差全忘了。 早上起来水了会谷,吃完饭出发。 同车 @Vsinger_洛天依 和 @JustinXaviel. 我和洛天依都不考钩组,所以把 JustinXaviel 送到地方之后…

UML在线工具的使用

UML在线编辑网站 https://plantuml.com/zh/class-diagram 模板(类方法显示) @startuml skinparam classAttributeIconSize 0 class Config {+load() +save() } @enduml

CSP2024-24

2A 题意:给定长度为 \(n\) 的非负整数数组 \(a\),求最小的 \(r−l+1\) 满足 \(l≤r,\sum_{i = l}^ra_i\) 是合数。 考虑全是正数的情况,答案一定 \(\le 4\),考虑一下每个数的奇偶性即可。 那么就把所有正数及其位置存下来,使得 \(b_i = a_{p_i}\),暴力检查 \(b\) 中长度为…

放开那代码让我来!——Cursor帮你写代码的奇妙之旅

让我们开门见山:编程很酷,但也很折磨人。那些长时间盯着屏幕,debug无休止的日子,只有程序员懂得它的酸爽。而就在这个编程焦虑的世界中,Cursor横空出世,带着一系列魔法功能,如同你手中的一根智能魔杖,让写代码变得像煮速冻面一样简单。 Cursor,一款基于AI的编程助手,…

Mathtype公式相关:在mathtype中添加任意维数矩阵的方法以及矩阵中省略号的问题;输入空格;输入花体字母;输入空心字母;输入空心数字

一、在mathtype中添加任意维数矩阵的方法以及矩阵中省略号的问题 使用mathtype创建任意维数的矩阵: 打开mathtype后可点击矩阵工具栏,再点击右下角的图形,具体情况如下图所示。点击之后会弹出一个对话框如下图所示,可在行列处输入自己想要的行数和列数。使用此方法创建的矩…

GIS转码的秋招历程与踩坑经历

本文介绍地理信息科学(GIS)专业的2024届应届生,在研三上学期期间,寻找后端研发、软件开发等IT方向工作的非科班转码秋招情况~本文介绍地理信息科学(GIS)专业的2024届应届生,在研三上学期期间,寻找后端研发、软件开发等IT方向工作的非科班转码秋招情况。首先,这篇文章一…

树状数组浅谈

什么是树状数组 树状数组是一种码量小,常数小,支持单点修改和区间查询的数据结构。 树状数组维护的信息和运算需要满足结合律并且可差分 注意gcd和max操作虽然满足结合律,但不可差分,因此不能使用树状数组维护 其实,树状数组能做的,线段树都能做,线段树能做的,树状数组…

Filebeat

Filebeat 简介 Filebeat用于转发和集中日志数据的轻量级传送程序。作为服务器上的代理安装,Filebeat监视指定的位置文件或位置,收集日志事件,并将他们转发到Elasticsearch 或Logstash进行索引。 架构图安装Filebeat 下载并安装 wget https://artifacts.elastic.co/download…

Tarjan算法及其应用 总结+详细讲解+详细代码注释

\(\text{Tarjan}\) 1.引入概念 1.强连通分量 1.定义 在有向图 \(G\) 中,强连通分量就是满足以下条件的 \(G\) 的子图:从任意一点出发,都有到达另一个点的路径。 不存在一个或者几个点,使得这个子图加入这些点后,这个子图还满足上一个性质。为什么要限定”在有向图中“而不…

三级数据库技术笔记

数据库应用系统开发方法 数据库应用系统生命周期 软件工程与软件开发方法 瀑布模型 快速原型模型 螺旋模型 DBAS生命周期 DBAS生命周期:项目规划、需求分析、系统设计、实现与部署、运行与维护 规划与分析 可行性分析:经济可行性、技术可行性、操作可行性、开发方案选择 需求…