mockito+junit完成单元测试
一:单元测试的特点
- 配合断言使用(可以杜绝System.out)
- 可以重复执行
- 不依赖环境
- 不会对数据产生影响
- spring的上下文环境不是必须的
- 一般都需要配合mock类框架来实现
二:常用的mock类框架
mockito
官网:Mockito framework site
另外现在像powermock和JMockito现在都不常用了;
三:Mockito的单独使用
(1)mock对象和spy对象
方法插桩 | 方法不插桩 | 作用对象 | 最佳实践 | |
mock | 执行插桩逻辑 | 返回mock对象的默认值 | 类、接口 | 被测试类或其依赖 |
spy | 执行插桩逻辑 | 调用真实方法 | 类、接口 | 被测试类 |
(2)初始化mock/spy对象的方式
方法一 | 方法二 | 方法三 | |
junit4 | @RunWith(MockitoJUnitRunner.class)+@Mock等注解 | Mockito.mock(X.class)等静态方法 | MockitoAnnotations.openMocks(this)+@Mock等注解 |
junit5 | @ExtendWith(MockitoExtension.class)+@Mock等注解 |
四:具体实例操作
Controller层:
@Slf4j
@RestController
@Validated
public class UserController{@Resourceprivate UserService userService;@GetMapping("/selectById")public UserVO selectById(@NotNull Long userId){return userService.selectById(userId);}@PostMapping("/add")public String add(@RequestBody @Validated UserAddReq addReq){userService.add(addReq.getUsername(),addReq.getPhone(),addReq.getfeatures());return ok;}
}
方法一:@ExtendWith(MockitoExtension.class)+@Mock等注解
@ExtendWith(MockitoExtension.class)
public class InitMockSpyMethod1{@mockprivate UserService mockUserService;@Spyprivate UserService spyUserService;@Testpublic void test1(){//true 判断某对象是不是mock对象System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());//false 判断某对象是不是apy对象System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());//true 判断某对象是不是spy对象System.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());//true 判断某对象是不是spy对象,因为spy是一种特殊的mock(spy对象是另一种不同类型的mock对象)System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetail(spyUserService).isMock());}
}
spy对象是一种特殊的mock对象
方法二:Mockito.mock(X.class)等静态方法
public class InitMockSpyMethod1{private UserService mockUserService;private UserService spyUserService;@BeforeEachpublic void init(){mockUserService = Mockito.mock(UserService.class);spyUserService = Mockito.spy(UserService.class);}@Testpublic void test1(){System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());System.out.println("Mockito.mockingDetails(mockUserService).isSpy() = " + Mockito.mockingDetails(mockUserService).isSpy());System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetails(spyUserService).isMock());}
}
方法三:MockitoAnnotations.openMocks(this)+@Mock等注解
public class InitMockSpyMethod1{@mockprivate UserService mockUserService;@Spyprivate UserService spyUserService;@BeforeEachpublic void init(){MockitoAnnotations.openMocks(this);}@Testpublic void test1(){//true 判断某对象是不是mock对象System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());//false 判断某对象是不是apy对象System.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());//true 判断某对象是不是spy对象System.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());//true 判断某对象是不是spy对象,因为spy是一种特殊的mock(spy对象是另一种不同类型的mock对象)System.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetail(spyUserService).isMock());}
}
五:参数匹配
参数匹配指的是:通过方法签名(参数)来指定哪些方法调用需要处理被处理(插桩、verify验证)
对于mock对象不会调用真实方法,直接返回mock对象的默认值;
默认值(int)、null(UserVO)、空集合(list)
六:方法插桩
指定调用某个方法时的行为(stubbing),达到相互隔离的目的
/**
*测试插桩时的参数匹配
*/
@Test
public void test2(){UserUpdateReq userUpdateReq1 = new UserUpdateReq();userUpdateReq1.setId(1L);userUpdateReq1.setPhone("1L");//指定参数为userUpdateReq1时调用mockUserService.modifyById(userUpdateReq1);Mockito.doReturn(99).when(mockUserService).modifyById(userUpdateReq1);int result1 = mockUserService.modifyById(userUpdateReq1);//运行结果为99System.out.println("result1 = " + result1);UserUpdateReq userUpdateReq2 = new UserUpdateReq();userUpdateReq2.setId(2L);userUpdateReq2.setPhone("2L");int result2 = mockUserService.modifyById(userUpdateReq2);//运行结果为0System.out.println("result2 = " + result2);
}
总结:
是告诉mockito当传入的是下面的参数这个类型时,才对其进插桩,若不是这个值,则不用对它进行插桩
若想要拦截某种类型的任意对象,则需要运用到:
ArgumentMatchers.any拦截UserUpdateReq类型的任意对象
校验:
add方法调用一次,校验通过。
private UserService mockUserService;@Testpublic void test4(){List<String> features = new ArrayList<>();mockUserService.add("实验","123",festures);//校验参数为"乐之者","123",festures,features的add方法调用了1次Mockito.verify(mockUserService,Mockito.times(2)).add("实验","123",festures);//报错 ,要么都用要么就都别用// Mockito.verify(mockUserService,Mockito.times(2)).add("实验","123",festures);//此时可以校验通过Mockito.verify(mockUserService,Mockito.times(2)).add(anyString(),anyString(),anyList());}}
但是有一点需要牢记的,除了any,还有(anyLong,anyString...),注意他们都不包括null,如果传null,还是不能被匹配的。
通过插桩,指定方法的返回值:
void返回值方法插桩 :
插桩的两种方式:
多次插桩:
其中when(mockList.size()).thenReturn(1).thenReturn(2).thenReturn(3)可以简写为when(mockList.size()).thenReturn(1,2,3);
thenAnswer指定插桩逻辑:
执行真正的原始方法:
verify的使用:
@InjectMocks注解的使用
1.被@InjectMocks标注的属性必须是实现类,因为mockito会创建对应的实例对象,默认创建的对象就是未经过mockito处理的普通对象。因此常配合@spy注解使其变成默认调用真实方法的mock对象。
2.mockito会使用spy,最终的结果就是,会把userFeatureService给注入到InjectMocks标注的变量所对应的对象里面去。
注入的原理:
相关文章:

mockito+junit完成单元测试
一:单元测试的特点 配合断言使用(可以杜绝System.out)可以重复执行不依赖环境不会对数据产生影响spring的上下文环境不是必须的一般都需要配合mock类框架来实现 二:常用的mock类框架 mockito 官网:Mockito framew…...

基于web的便捷饭店点餐小程序的设计与实现(lw+演示+源码+运行)
摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱,出错率高,信息安全…...

CUDA环境安装终极指南——Linux(其它系统也一样)
文章目录 前言检查驱动配置nvcc安装cudnn完活 前言 不用看其它文章了,这篇文章保你不踩任何坑,安装方法简单快速 检查驱动 检查驱动是否安装,输入以下命令 nvidia-smi如果驱动已经安装,则可跳过此步,否则ÿ…...

安卓开发之登录页面(跳转版)
目录 前言:基础夯实:效果展示:核心代码:网盘源码: 前言: 熟悉安卓开发的基础知识,了解,弹窗,两个页面进行跳转,页面的布局,按钮,文本…...

solidworks学习6吊环-20241030
solidworks学习6吊环 图 1 使用到的命名:拉伸曲面,旋转曲面,镜像实体,剪裁曲面, 前视基准面绘制 图 2 绘制旋转轴 图 3 旋转曲面 图 4 上视基准面绘制,标准圆边尺寸的时候需要按住shift键标注&#x…...

数据结构和算法-动态规划(3)-经典问题
动态规划常见问题 打家劫舍 题目 [力扣198] 198. 打家劫舍 - 力扣(LeetCode) 题目描述 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&…...

Java算法-一维前缀和与差分
一、一维前缀和 ① 什么是一维前缀和? 📚 其实通过名字就能知道" 一维前缀和 "的意思: 通过一个一维数组"arr1"而创建的另一个一维数组"arr2","arr2"的每一个元素都是"arr1"…...

Elasticsearch 安装教程:驾驭数据海洋的星际导航仪
目录 一、准备工作1. ES的下载 二、安装步骤三、注意事项四、启动报错1. org.elasticsearch.bootstrap.StartupException: java.lang.RuntimeException: can not run elasticsearch as root2. max virtual memory areas vm.max_map_count [65530] is too low, increase to at l…...

【解决方案】微信小程序如何使用 ProtoBuf 进行 WebSocket 通信
前言 故事背景 简单说下背景,项目中需要用 ProtoBuf 协议转换请求参数,并通过 WebSocket 进行双向通信。重点!一个是 web端(Vue3 TS),一个是微信小程序端(原生 JS)。 剧情发展 …...

独立游戏开发者面临的挑战与困境
在当今竞争激烈的游戏市场中,独立游戏开发者面临着诸多挑战与困境。从游戏版号申请到游戏被抄袭,再到产品同质化以及流量获取难题,乃至外包内卷现象,每一个环节都考验着开发者的智慧与毅力。以下是对这些挑战与闲境的详细分析。 …...

KVM 虚拟机Anolis OS 8.9 下利用宝塔面板中的 Docker 配置 Nextcloud + onlyoffice
第一部分:安装配置 nextcloud 准备 (1)启动一个 Anolis OS 8.9 虚拟机,见下图。该虚拟机为 anlisos8…0.2 虚拟机的 ssh、hostname 、IP地址都已配置好。 (2)宝塔面板也已安装好docker 一、环境 do…...
串口扫盲TTL,TX/TR/GND
1. 串口扫盲TTL,TX/TR/GND 1. 串口扫盲TTL,TX/TR/GND 1.1. TTL1.2. USB转TTL1.3. 串口通信1.4. 引脚缩写1.5. 参考资料 1.1. TTL TX(TXD) 来源于 Transmit 一词,意思为发送,发射RX(RXD) 来源于 Receive 一词 意思为接收,收到GND 地线&…...

Python酷库之旅-第三方库Pandas(181)
目录 一、用法精讲 836、pandas.api.types.is_file_like函数 836-1、语法 836-2、参数 836-3、功能 836-4、返回值 836-5、说明 836-6、用法 836-6-1、数据准备 836-6-2、代码示例 836-6-3、结果输出 837、pandas.api.types.is_list_like函数 837-1、语法 837-2、…...

Python数据分析NumPy和pandas(十七、pandas 二进制格式文件处理)
以二进制格式存储(或序列化)数据的一种简单方法是使用 Python 的内置 pickle 模块。同时,pandas 构造的对象都有一个 to_pickle 方法,该方法以 pickle 格式将数据写入磁盘。 我们先把之前示例用到的ex1.csv文件加载到pandas对象中…...
matlab计算相关物理参数
function Rx1Jetfire1_1(di,Ct,Tf,Tj,alpha,Ma,Mf,RH,P0,P,k,Cd,elta,deltaHc,tau,directory) % 一共15个独立变量,为了方便输入修改,所有变量存入Jetfire1_1excel表, % dj为孔口直径,m;Ct为燃料空气混合摩尔系数,可…...
nmcli、ip、ifcfg配置网络区分方法
文章目录 一、检查NetworkManager状态使用nmcli命令:检查NetworkManager服务状态: 二、检查ip命令的使用三、检查ifcfg文件查看/etc/sysconfig/network-scripts/目录:查看/etc/network/interfaces文件(针对Debian系)&a…...

第四届智能电力与系统国际学术会议(ICIPS 2024)
文章目录 一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题六、咨询 一、会议详情 二、重要信息 大会官网:https://ais.cn/u/vEbMBz提交检索:EI Compendex、IEEE Xplore、Scopus 三、大会介绍 四、出席嘉宾 五、征稿主题 如想"投稿…...
区块链样题第4套解析 后端应用开发部分
任务3-2:区块链应用后端开发 使用JAVA-SDK与区块链进行交互,通过solc2Java工具将Solidity智能合约转译为可供Java调用的文件,实现区块链编程。 前言:题目只是单纯考了对于fisco-java-sdk的简单使用 教程参考: 1.这边建议还是学习完JavaWeb课程。 黑马程序员JavaWeb...

C语言实现408考研真题2016年43题
#include <iostream> // 定义分区函数,返回两个子数组之和的差值 int setPartition(int a[], int n) { int pivotkey, low 0, low0 0, high n - 1, high0 n - 1, flag 1, k n / 2, i; int s1 0, s2 0; // 当low等于k-1,…...

2024年,Rust开发语言,现在怎么样了?
Rust开发语言有着一些其他语言明显的优势,但也充满着争议,难上手、学习陡峭等。 Rust 是由 Mozilla 主导开发的通用、编译型编程语言,2010年首次公开。 在 Stack Overflow 的年度开发者调查报告中,Rust 连续多年被评为“最受喜爱…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...