当前位置: 首页 > news >正文

JUNIT5+Mockito单元测试

文章目录

  • 1、前言
  • 2、Maven依赖
    • 2.1 JDK21+SpringBoot版本基于3.1.0
    • 2.2 JDK17+SpringBoot版本基于2.2.5.RELEASE
  • 3、业务代码
  • 4、单元测试

1、前言

之前写过一篇使用testMe自动生成单元测试用例,使用的是junit4来编写的单元测试用例,目前很多新项目都已经使用JDK11+以及SpringBoot3+。本次基于junit5+Mockito来编写单元测试。

2、Maven依赖

2.1 JDK21+SpringBoot版本基于3.1.0

SpringBoot依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.0</version><relativePath/> <!-- lookup parent from repository --></parent>
 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.objenesis</groupId><artifactId>objenesis</artifactId></exclusion></exclusions></dependency>

mockito依赖

<!--junit5单元测试--><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>5.3.1</version></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>5.3.1</version></dependency>

lombok依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>edge-SNAPSHOT</version></dependency>

2.2 JDK17+SpringBoot版本基于2.2.5.RELEASE

SpringBoot依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.5.RELEASE</version></parent>

Junit依赖

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.8.2</version></dependency>

mockito依赖

<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>5.2.0</version><exclusions><exclusion><groupId>net.bytebuddy</groupId><artifactId>byte-buddy</artifactId></exclusion><exclusion><groupId>net.bytebuddy</groupId><artifactId>byte-buddy-agent</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>5.2.0</version></dependency><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy</artifactId><version>1.14.1</version></dependency><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy-agent</artifactId><version>1.14.1</version></dependency>

lombok依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency>

3、业务代码

package com.summer.toolkit.mock;import com.alibaba.fastjson.JSON;
import com.summer.toolkit.dto.UserDto;
import com.summer.toolkit.exception.BizException;
import com.summer.toolkit.executor.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;@Slf4j
@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserManager userManager;@Overridepublic Long createUser(UserDto userDto) {log.info("创建用户入参:{}", JSON.toJSONString(userDto));String name = userDto.getUsername();if (StringUtils.isBlank(name)) {log.error("用户名称不能为空");throw new BizException("用户名称不能为空");}Long id = userManager.createUser(userDto);log.info("创建用户出参:{}", id);return id;}@Overridepublic Boolean updateUser(UserDto userDto) {log.info("更新用户入参:{}", JSON.toJSONString(userDto));Long id = userDto.getId();String name = userDto.getUsername();if (Objects.isNull(id)) {log.error("用户主键不能为空");throw new BizException("用户主键不能为空");}if (StringUtils.isBlank(name)) {log.error("用户名称不能为空");throw new BizException("用户名称不能为空");}UserDto user = userManager.getUser(userDto);if (Objects.isNull(user)) {log.error("用户不存在");throw new BizException("用户不存在");}Boolean result = userManager.updateUser(userDto);log.info("更新用户出参:{}", result);return result;}@Overridepublic UserDto getUser(UserDto userDto) {log.info("获取用户入参:{}", JSON.toJSONString(userDto));Long id = userDto.getId();if (Objects.isNull(id)) {log.error("用户主键不能为空");throw new BizException("用户主键不能为空");}UserDto user = userManager.getUser(userDto);log.info("获取用户出参:{}", user);return user;}@Overridepublic Boolean batchCreateUser(List<UserDto> list) {log.info("批量创建用户入参:{}", JSON.toJSONString(list));if (CollectionUtils.isEmpty(list)) {log.error("入参集合不能为空");throw new BizException("入参集合不能为空");}int size = 10;long keepAliveTime = 60;long start = System.currentTimeMillis();BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10000);ThreadFactory threadFactory = new DefaultThreadFactory("executor");ExecutorService executorService= new ThreadPoolExecutor(size, size, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);List<CompletableFuture<Boolean>> futureList = new ArrayList<>();for (UserDto userDto : list) {CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {log.info("当前线程名称:{}", Thread.currentThread());try {Long id = userManager.createUser(userDto);TimeUnit.SECONDS.sleep(3L);log.info("线程:{} id={} done", Thread.currentThread(), id);return Boolean.TRUE;} catch (InterruptedException e) {log.error("创建用户异常:{}", e.getMessage(), e);return Boolean.FALSE;}}, executorService);futureList.add(future);}Boolean result = Boolean.TRUE;try {CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).get(10, TimeUnit.SECONDS);for (CompletableFuture<Boolean> future : futureList) {Boolean back = future.get();if (Boolean.FALSE.equals(back)) {result = Boolean.FALSE;}}} catch (Exception e) {log.error("创建用户异常:{}", e.getMessage(), e);result = Boolean.FALSE;}long end = System.currentTimeMillis();log.info("批量创建用户耗时:{}", (end - start));log.info("批量创建用户出参:{}", result);return result;}}

4、单元测试

package com.summer.toolkit.service;import com.summer.toolkit.dto.UserDto;
import com.summer.toolkit.exception.BizException;
import com.summer.toolkit.mock.UserManager;
import com.summer.toolkit.mock.UserServiceImpl;
import com.summer.toolkit.util.FileUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;import java.util.ArrayList;
import java.util.Date;
import java.util.List;import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;@ExtendWith(MockitoExtension.class)
@EnabledIfEnvironmentVariable(named = "DEBUG", matches = "true")
public class UserServiceTest {@Mockprivate Logger log;@Mockprivate UserManager userManager;@InjectMocksprivate UserServiceImpl userService;@Testpublic void testCreateUser() {// 模拟依赖方法Mockito.when(userManager.createUser(any())).thenReturn(Long.valueOf(1));// 调用被测方法UserDto userDto = this.buildUserDto();Long result = userService.createUser(userDto);// 验证方法结果Long expect = 1L;Assertions.assertEquals(expect, result);// 验证方法是否被调用Mockito.verify(userManager).createUser(userDto);// 验证依赖对象只有这一个Mockito.verifyNoMoreInteractions(userManager);}@Testpublic void testUpdateUser() {// 模拟依赖方法Mockito.when(userManager.updateUser(any())).thenReturn(Boolean.TRUE);Mockito.when(userManager.getUser(any())).thenReturn(new UserDto());// 调用被测方法UserDto userDto = this.buildUserDto();userDto.setId(1L);Boolean result = userService.updateUser(userDto);// 验证方法结果Assertions.assertEquals(Boolean.TRUE, result);// 验证方法是否被调用Mockito.verify(userManager).getUser(any());Mockito.verify(userManager).updateUser(any());}@Testpublic void testGetUser() {// 模拟依赖方法Mockito.when(userManager.getUser(any())).thenReturn(new UserDto());// 调用被测方法UserDto userDto = this.buildUserDto();userDto.setId(1L);UserDto result = userService.getUser(userDto);// 验证方法结果Assertions.assertNotNull(result);// 验证方法是否被调用Mockito.verify(userManager).getUser(userDto);}@Testpublic void testBatchCreateUser() {// 模拟依赖方法,指定单个异常类型Mockito.when(userManager.createUser(any())).thenThrow(BizException.class);// 调用被测方法List<UserDto> param = new ArrayList<>();UserDto userDto = this.buildUserDto();param.add(userDto);Boolean result = userService.batchCreateUser(param);// 验证方法结果Assertions.assertEquals(Boolean.FALSE, result);// 验证方法是否被调用,默认一次Mockito.verify(userManager).createUser(userDto);// 验证方法是否被调用了1次Mockito.verify(userManager, Mockito.times(1)).createUser(any());}@Testpublic void testBatchCreateUserTimes() {// 模拟依赖方法,指定单个异常类型Mockito.when(userManager.createUser(any())).thenReturn(1L);// 调用被测方法List<UserDto> param = new ArrayList<>();UserDto userDto = this.buildUserDto();param.add(userDto);param.add(userDto);param.add(userDto);Boolean result = userService.batchCreateUser(param);// 验证方法结果Assertions.assertEquals(Boolean.TRUE, result);// 验证方法是否被调用了3次Mockito.verify(userManager, Mockito.times(3)).createUser(any());}@Testpublic void testFileUtils() {// 构建对象List<String> list = new ArrayList<>();list.add("1");list.add("2");// 模拟对应的类// JDK11及以上版本中,try块中的变量可以在外部声明MockedStatic<FileUtils> mocked = Mockito.mockStatic(FileUtils.class);try (mocked) {// 模拟依赖静态方法mocked.when(() -> FileUtils.readFileAllLines(anyString())).thenReturn(list);// 调用被测方法List<String> lines = FileUtils.readFileAllLines(anyString());// 验证方法结果Assertions.assertEquals(list.size(), lines.size());} catch (Exception e) {log.error("模拟静态方法异常:{}", e.getMessage(), e);}}/*** 构建用户数据传输对象** @return UserDto 返回构建好的用户数据传输对象*/private UserDto buildUserDto() {UserDto userDto = new UserDto();userDto.setUsername("小明");userDto.setBirthday(new Date());userDto.setAddress("北京市大兴区亦庄经济开发区");userDto.setComment("加麻加辣");userDto.setGender(1);return userDto;}}

相关文章:

JUNIT5+Mockito单元测试

文章目录 1、前言2、Maven依赖2.1 JDK21SpringBoot版本基于3.1.02.2 JDK17SpringBoot版本基于2.2.5.RELEASE 3、业务代码4、单元测试 1、前言 之前写过一篇使用testMe自动生成单元测试用例&#xff0c;使用的是junit4来编写的单元测试用例&#xff0c;目前很多新项目都已经使用…...

【C#】【SAP2000】读取SAP2000中所有Frame对象的应力比到Grasshopper中

if (build true) {// 连接到正在运行的 SAP2000// 使用 System.Runtime.InteropServices.Marshal.GetActiveObject 方法获取正在运行的 SAP2000 实例cOAPI mySapObject (cOAPI)System.Runtime.InteropServices.Marshal.GetActiveObject("CSI.SAP2000.API.SapObject"…...

一台服务器部署两个独立的mysql实例

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…...

SpringBoot(Lombok + Spring Initailizr + yaml)

1.Lombok 1.基本介绍 2.应用实例 1.pom.xml 引入Lombok&#xff0c;使用版本仲裁 <!--导入springboot父工程--><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version&g…...

数据库基础知识超详细解析~‍(进阶/复习版)

文章目录 前言一、数据库的操作1.登入数据库2.创建数据库3.显示当前数据库4.使用数据库5.删除数据库 二、常用数据类型三、数据库的约束1约束类型2NULL约束3UNIQUE:唯一约束4DEFAULT&#xff1a;默认值约束5 PRIMARY KEY&#xff1a;主键约束6 FOREIGN KEY&#xff1a;外键约束…...

创建对象的方法有哪些

创建对象的方法主要取决于你使用的编程语言和上下文。下面我将列出一些主流编程语言中创建对象的方法&#xff1a; Python: 使用类定义和__init__方法&#xff1a; pythonclass MyClass: def __init__(self, name): self.name nameobj MyClass("Alice") 1.使用工厂…...

Oracle 10g字符编码

pl/sql developer查询数据时出现乱码&#xff0c;主要检查如下&#xff1a; 1、检查服务器编码 select * from v$nls_parameters;select * from nls_database_parameters;select userenv(language) from dual; 2、查看数据库可用字符集参数设置 select * from v$nls_valid_val…...

掌握抽象基础之20个必备原则,看完你还不会,你打我

抽象基础之20个必备原则 1. 面向对象编程&#xff08;OOP&#xff09;中抽象原则背后的基本思想是什么&#xff1f;2.抽象和封装的区别&#xff1f;3.提供一个现实生活中说明抽象的例子4.在编程语言中如何实现抽象&#xff1f;5.定义抽象类6.提供一个抽象类的真实世界场景7.解释…...

设计模式 -- 2:策略模式

目录 总结部分&#xff1a;策略模式的优点部分代码部分 总结部分&#xff1a; 策略模式和简单工厂模式很像 区别在于 简单工厂模式 需求的是由工程创造的类 去给客户直接答案 而策略模式在于 我有主体 一个主体 根据策略的不同来进行不同的计算 我的主体就负责收钱 然后调度相…...

【快速上手ProtoBuf】proto 3 语法详解

1 &#x1f351;字段规则&#x1f351; 消息的字段可以⽤下⾯⼏种规则来修饰&#xff1a; singular &#xff1a;消息中可以包含该字段零次或⼀次&#xff08;不超过⼀次&#xff09;。 proto3 语法中&#xff0c;字段默认使⽤该规则。repeated &#xff1a;消息中可以包含该…...

人工智能的幽默“失误”

人工智能迷惑行为大赏 随着ChatGPT热度的攀升&#xff0c;越来越多的公司也相继推出了自己的AI大模型&#xff0c;如文心一言、通义千问等。各大应用也开始内置AI玩法&#xff0c;如抖音的AI特效&#xff5e;在使用过程中往往会遇到一些问题&#xff0c;让你不得不怀疑&#x…...

js的异步请求?

在 JavaScript 中&#xff0c;进行异步请求通常涉及到使用 XMLHttpRequest 对象或者更现代的 Fetch API 或 Axios 库。这些工具可以帮助我们向服务器发送请求并在后台获取数据&#xff0c;而不会阻塞页面的其他操作。 下面是一个简单的示例&#xff0c;演示如何使用原生的 XML…...

华润对象存储(OBS)工具类

目录 一、备注二、工具类三、对象存储放在内网&#xff0c;如何实现外网访问 一、备注 1、ObjectBasicInfo、ObjectDetailInfo、ResultBody这三个类可自行替换或者去掉 二、工具类 package com.xxx.util;import com.amazonaws.HttpMethod; import com.amazonaws.auth.AWSStat…...

强缓存和协商缓存的区别?

协商缓存和强缓存是 HTTP 缓存机制中的两种不同的策略&#xff0c;用于减少网络请求并提高网页加载速度。它们之间的主要区别在于缓存的验证方式和服务器返回的响应头。 强缓存&#xff1a; 强缓存是基于过期时间&#xff08;Expires&#xff09;和缓存标识&#xff08;Cache…...

ChatGPT提问技巧——对抗性提示

ChatGPT提问技巧——对抗性提示 对抗性提示是一种允许模型生成能够抵御某些类型的攻击或偏差的文本的技术。这种技术可用于训练更健壮、更能抵御某些类型的攻击或偏差的模型。 要在 ChatGPT 中使用对抗性提示&#xff0c;应为模型提供一个提示&#xff0c;该提示的设计应使模…...

openGauss使用BenchmarkSQL进行性能测试(上)

一、前言 本文提供openGauss使用BenchmarkSQL进行性能测试的方法和测试数据报告。 BenchmarkSQL&#xff0c;一个JDBC基准测试工具&#xff0c;内嵌了TPC-C测试脚本&#xff0c;支持很多数据库&#xff0c;如PostgreSQL、Oracle和Mysql等。 TPC-C是专门针对联机交易处理系统…...

Java的线程池机制

Java的线程池机制是用来管理和调度多个线程的工具。通过线程池&#xff0c;可以避免频繁地创建和销毁线程&#xff0c;提高线程的复用率&#xff0c;减少资源消耗。 Java中提供了几种不同类型的线程池&#xff1a; 1、FixedThreadPool&#xff08;固定大小线程池&#xff09;…...

EasyCode 插件的具体使用

前言 EasyCode 是基于IntelliJ IDEA Ultimate版开发的一个代码生成插件&#xff0c;主要通过自定义模板&#xff08;基于velocity&#xff09;来生成各种你想要的代码。通常用于生成Entity、Dao、Service、Controller。如果你动手能力强还可以用于生成HTML、JS、PHP等代码。理…...

Ypay源支付6.9无授权聚合免签系统可运营源码

YPay是一款专为个人站长设计的聚合免签系统&#xff0c;YPay基于高性能的ThinkPHP 6.1.2 Layui PearAdmin架构&#xff0c;提供了实时监控和管理的功能&#xff0c;让您随时随地掌握系统运营情况。 说明 Ypay源支付6.9无授权聚合免签系统可运营源码 已搭建测试无加密版本…...

SpringBoot+Vue项目报错(问题已解决)

1、错误日志 2、分析原因&#xff1a; JWT strings must contain exactly 2 period characters. Found: 0 JWT字符串必须包含2个句号字符。发现:0 分析&#xff1a;可以判断出大概可能是token格式出现了问题 3、参考 http://t.csdnimg.cn/hfEiY 4、检查后端代码是否出现问…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

C++_哈希表

本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、基础概念 1. 哈希核心思想&#xff1a; 哈希函数的作用&#xff1a;通过此函数建立一个Key与存储位置之间的映射关系。理想目标&#xff1a;实现…...

node.js的初步学习

那什么是node.js呢&#xff1f; 和JavaScript又是什么关系呢&#xff1f; node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说&#xff0c; 需要在node.js的环境上进行当JavaScript作为前端开发语言来说&#xff0c;需要在浏览器的环境上进行 Node.js 可…...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...