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

Springboot结合Mockito写单元测试实践和原理

文章目录

  • 前言
  • 一、使用
    • 最佳实践
    • 使用场景
    • @SpyBean失效场景
    • 解决Mock失效的问题
      • 避免FactoryBean的实现方式
      • 使用@MockBean,但是要指定name
    • 个人推荐
  • 二、原理
    • 1. @MockBean
    • 2.@SpyBean
    • 方法调用
  • 总结


前言

相信看我博客的都是javaer,工作中一般都是使用Springboot框架。
之前介绍过,可以利用@Transactional注解实现单测方法回滚,其实大家都知道Springboot-Test里面集成了Mockito,今天我们来介绍下怎么使用,以及原理是什么。


一、使用

最佳实践

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ApplicationLoader.class)
public abstract class BaseTest {@SpyBeanprotected EcmsGateway ecmsGateway;// 注意这行,是数据库查询的mapper,需要配置name属性。@MockBean(name = "basicUserInfoPOExtMapper")protected BasicUserInfoPOExtMapper basicUserInfoPOExtMapper;}@Before@SneakyThrows //这个是lombok的注解,还是挺好用的public void init() {
Mockito.doReturn(Collections.singletonList(userInfoPO)).when(basicUserInfoPOExtMapper).listBasicUserInfo();
Mockito.doReturn(Collections.singletonList(contractBaseInfo)).when(ecmsGateway).queryMainContractList(Mockito.anyList());}

**注意mybatis的mapper必须使用@MockBean注解,且必须配置name属性。**但是也因此导致该mapper作用域下的所有方法如果没有指定返回范式,就会返回空对象。

使用逻辑也很简单,就是通过MockBean和SpyBean对spring容器里注入的bean进行改造,然后在方法执行之前,通过Mockito的方法来指定当方法运行时,mock返回值。
需要注意的是
MockBean注解注入的属性,所有的方法调用,只要不指定返回范式和Mock对象,都是返回一个空的数据,null或者空的容器;而SpyBean注解注入的属性,默认方法调用还是走真实的链路调用,只有指定了返回范式的调用才会返回Mock的数据。

使用场景

一般情况下,咱们需要mock数据的场景是对于RPC调用,或者数据库查询(当然这个其实也是一种RPC)调用。
需要注意,很多同学发现Mock数据库查询会失效,具体原因和下面的是同一种情况!!!

@SpyBean失效场景

通过FactoryBean返回的对象类型是一个proxy时

Caused by: org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.sun.proxy.$Proxy146
注意这句报错!!!!!!
Mockito cannot mock/spy because :- final classat org.springframework.boot.test.mock.mockito.SpyDefinition.createSpy(SpyDefinition.java:103)at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.createSpyIfNecessary(MockitoPostProcessor.java:358)at org.springframework.boot.test.mock.mockito.MockitoPostProcessor$SpyPostProcessor.createSpyIfNecessary(MockitoPostProcessor.java:496)at org.springframework.boot.test.mock.mockito.MockitoPostProcessor$SpyPostProcessor.postProcessAfterInitialization(MockitoPostProcessor.java:492)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:431)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1836)at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)... 106 more

解决Mock失效的问题

避免FactoryBean的实现方式

目前mybatis针对poMapper的实现都是通过MapperFactoryBean实现的,所以,最简单的方式,可以基于mapper封装repository层,然后对repository层的对象添加@MockBean或者@SpyBean,进行调用。
譬如:

@Repository
public class BasicUserInfoRepository implements IBasicUserInfoRepository {@Resourceprivate BasicUserInfoPOExtMapper basicUserInfoPOExtMapper;
}@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootStudyApplication.class)
public class BaseTest {@SpyBeanprotected IBasicUserInfoRepository iBasicUserInfoRepository;}

使用@MockBean,但是要指定name

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootStudyApplication.class)
public class BaseTest {@MockBean(name = "basicUserInfoPOExtMapper")protected BasicUserInfoPOExtMapper basicUserInfoPOExtMapper;}

个人推荐

其实针对查询数据库的场景,个人还是推荐通过@Transactional注解达到数据回滚来实现查询数据的诉求,毕竟要是通过对poMapper添加@MockBean使得数据库查询能够Mock,但是由此导致了该poMapper的所有方法都需要指定返回范式。实例如下:

   @Transactional@Testpublic void testReceive() {// 前置将任务状态修改Long jobId = 255L;SePriceJob priceJob = new SePriceJob();priceJob.setId(jobId);priceJob.setAcceptType(JobAcceptType.CREATE_SUPPLIER_MAKE_UP.getAcceptType());priceJob.setStatus(PriceJobStatus.DONE.getStatus());priceJob.setTaskStatus(PriceJobTaskStatus.PROCESSING.getStatus());priceJobMapper.updateByPrimaryKeySelective(priceJob, SePriceJob.Column.acceptType, SePriceJob.Column.status, SePriceJob.Column.taskStatus);List<SePriceJob> priceJobList = priceJobMapper.selectByExample(SePriceJobExample.newAndCreateCriteria().andIdEqualTo(jobId).example());assert priceJobList.get(0).getTaskStatus().equals(PriceJobTaskStatus.PROCESSING.getStatus());}

二、原理

1. @MockBean

@MockBean注解的实现原理
需要注意的是MockBean有时候需要指定name属性,否则默认注入到Spring容器中的对象beanName是类的全限定名,导致其他bean在注入的时候获取到的不是该mockBean。

2.@SpyBean

@SpyBean注解对于原本bean是通过FactoryBean添加到容器,且被proxy过的实例,是没法实现Mock的。
@SpyBean注解的实现原理
可以看到不管是@MockBean还是@SpyBean,都是给spring的bean创建增加一个MockMethodInterceptor。
区别在于

1. @MockBean创建的mock对象是直接new出来的,而且只有MockMethodInterceptor这一个advisor;而@SpyBean是通过给spring容器创建的对象增加一个advisor:MockMethodInterceptor
2. 那MockMethodInterceptor在执行的时候是怎么区分当前对象到底是@MockBean还是@SpyBean修饰呢?MockMethodInterceptor对象有个属性MockCreationSettings mockCreationSettings,它有个属性defaultAnswer。@MockBean指定了该属性为Answers.RETURNS_DEFAULTS,而@SpyBean通过MockitoPostProcessor的createSpyIfNecessary,给指定的取值是Mockito.CALLS_REAL_METHODS

方法调用

方法调用的源码就不贴了,简单来说就是给MockMethodInterceptor实例增加一个返回范式,譬如创建一个matcher,指定该matcher命中时,返回某个对象;实际运行时,通过匹配matcher来决定是否返回Mock结果。


总结

  1. 文章主要讲了Springboot中的@MockBean和@SpyBean的使用场景和简单原理。
  2. 大家使用数据库一般都是通过spring-mybatis将mapper注入到spring容器的,导致使用@SpyBean不会生效,推荐使用@MockBean,同时指定name属性来实现数据库查询的返回Mock。当然笔者更推荐大家使用@Transactional注解实现回滚来达到数据库查询结果的设置。

相关文章:

Springboot结合Mockito写单元测试实践和原理

文章目录 前言一、使用最佳实践使用场景SpyBean失效场景解决Mock失效的问题避免FactoryBean的实现方式使用MockBean&#xff0c;但是要指定name 个人推荐 二、原理1. MockBean2.SpyBean方法调用 总结 前言 相信看我博客的都是javaer&#xff0c;工作中一般都是使用Springboot框…...

操作系统之微内核架构

宏内核相反&#xff0c;微内核架构提倡功能尽可能少&#xff0c;只提供进程调度、处理中断、内存映射、进程间通信等功能。微内核架构是不能够提供什么实际功能的&#xff0c;而内存管理、进程管理、设备管理和文件管理服务等&#xff0c;都被做成一个个服务进程&#xff0c;它…...

24---WPF缓存

一、什么是缓存&#xff1a; 1.缓存指的是将需要频繁访问的网络内容存放在离用户较近、访问速度更快的系统中&#xff0c;以提高内容访问速度的一种技术。缓存服务器就是存放频繁访问内容的服务器。 2.缓存就是一个临时存放区域--离用户比较近 二、作用--意义---如果系统出现故…...

vite+vue3.0 使用tailwindcss

参考资料&#xff1a; 安装 - TailwindCSS中文文档 | TailwindCSS中文网 npm install -D tailwindcss npm install postcss npm install autoprefixer npx tailwindcss init -p 生成/src/tailwind.config.js和/src/postcss.config.js配置文件 在/src/tailwind.config.js配置文件…...

C++QT---QT-day3

使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否为&…...

小程序如何搭建在服务器上

小程序可以通过搭建在服务器上&#xff0c;来实现跨平台的访问和使用。以下是搭建小程序在服务器上的步骤&#xff1a; 安装Node.js&#xff1a;首先&#xff0c;你需要在服务器上安装Node.js。你可以从Node.js的官方网站下载并安装。 安装微信开发者工具&#xff1a;然后&…...

JavaEE初阶学习:Servlet

1.Servlet 是什么 Servlet 是一种 Java 程序&#xff0c;用于在 Web 服务器上处理客户端请求和响应。Servlet 可以接收来自客户端&#xff08;浏览器、移动应用等&#xff09;的 HTTP 请求&#xff0c;并生成 HTML 页面或其他格式的数据&#xff0c;然后将响应发送回客户端。S…...

黑白二维码不好看,那么快学习改色的方法吧

现在经常会看到很多的二维码不是黑白图案&#xff0c;可以是其他纯色或者渐变色等样式的&#xff0c;那么怎么将黑白二维码改成其他鲜艳好看的颜色呢&#xff1f;一般想要修改普通样式的二维码可以用二维码美化生成器来处理&#xff0c;只需要上传二维码图片&#xff0c;就可以…...

coreldraw2024版本有哪些新增功能?

有小伙伴在用电脑查找软件程序的时候&#xff0c;看到了一款叫cdr软件的应用&#xff0c;自己之前没接触过&#xff0c;不知道cdr是什么软件&#xff1f;cdr软件是干什么的&#xff1f;十分好奇。其实它是一款平面设计软件&#xff0c;下面就给大家介绍下相关的cdr软件的知识。…...

2023最新Office2021专业增强版安装使用教程

Microsoft Office专业增强版2021是一套办公软件套装&#xff0c;包含了Word、Excel、PowerPoint、Outlook、Access、Publisher、OneNote、Teams等应用程序。这个版本是在Office 365的基础上推出的新版本&#xff0c;与之前的Office版本相比&#xff0c;增强了许多功能。也是目前…...

实时配送跟踪功能的实现:外卖跑腿小程序的技术挑战

在当今数字化时代&#xff0c;外卖和跑腿服务已经成为了生活中不可或缺的一部分。为了提供更好的用户体验&#xff0c;外卖跑腿小程序越来越注重实时配送跟踪功能的实现。这项技术挑战旨在确保顾客可以方便地跟踪他们的订单&#xff0c;以及配送员可以高效地完成送货任务。本文…...

react实现一维表格、键值对数据表格key value表格

UI画的需求很抽象&#xff0c;直接把数据铺开&#xff0c;不能直接用antd组件了 上一行是name&#xff0c;下一行是value&#xff0c;总数不定&#xff0c;最后前端还要显示求和 class OneDimensionTable extends React.Component { render() {const { data } this.props;le…...

个人微信CRM客户管理系统怎么选?功能介绍

现在市面上有许多种类的个人微信CRM客户管理系统可供选择&#xff0c;因此&#xff0c;我们需要选择最适合自己需求的微信管理系统CRM&#xff0c;最重要的是根据您的需求和期望的功能来进行筛选。 如何选择适合自己的微信CRM客户管理系统&#xff1f; 现在市面上的系统五花八…...

Mac Intellij Idea get/set方法快捷键

Control Retrun(回车键) Command n 参考&#xff1a; Mac Intellij Idea get/set方法快捷键-CSDN博客...

并发程序设计

一、进程的创建和回收 一、进程的概念 1、进程&#xff01;程序 程序是静态的&#xff0c;而进程是动态的 2、进程和程序的区别 1&#xff09;进程控制块中包含进程的属性 2&#xff09;程序在磁盘里面&#xff0c;堆栈都是在内存中&#xff0c;程序运行起来都在内存中 3…...

openGauss学习笔记-104 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书替换

文章目录 openGauss学习笔记-104 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书替换104.1 操作场景104.2 前提条件104.3 注意事项104.4 操作步骤 openGauss学习笔记-104 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书替换 openGaus…...

react仿照antd progress实现可自定义颜色的直角矩形进度条

可传颜色、带滑块的直角进度条 很歹毒的UI设计&#xff08;真的很丑&#xff09; 实现&#xff1a; class RankProgress extends React.Component {render() {const { percent, progressColor } this.props;return (<div className{styles.progress}><div classNam…...

【网络安全】被恶意攻击的IP地址有多可怕?

被恶意攻击的IP地址可以导致一系列问题&#xff0c;其严重性和可怕程度取决于攻击的性质、目标、攻击者的动机以及受影响的系统或组织。以下是一些可能出现的问题和可怕性的因素&#xff1a; 数据泄露和盗窃&#xff1a;攻击者可能试图入侵系统&#xff0c;窃取敏感数据&#x…...

Guava-RateLimiter详解

简介&#xff1a; 常用的限流算法有漏桶算法和令牌桶算法&#xff0c;guava的RateLimiter使用的是令牌桶算法&#xff0c;也就是以固定的频率向桶中放入令牌&#xff0c;例如一秒钟10枚令牌&#xff0c;实际业务在每次响应请求之前都从桶中获取令牌&#xff0c;只有取到令牌的请…...

【C++11】右值引用、移动构造、移动赋值、完美转发 的原理介绍

文章目录 一、概念1.1 左值1.2 左值引用1.3 什么是右值&#xff1f;1.4 什么是右值引用&#xff1f;对于参数左值还是右值的不同&#xff0c;是被重载支持的左值引用的使用场景 和 缺陷 二、移动语义2.1 移动拷贝构造2.2 移动赋值 三、右值引用 与 STL3.1 移动拷贝构造 和 赋值…...

Hitboxer:3分钟解决游戏按键冲突的SOCD重映射利器

Hitboxer&#xff1a;3分钟解决游戏按键冲突的SOCD重映射利器 【免费下载链接】socd Key remapper for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 你是否在激烈的游戏对战中因按键冲突而错失良机&#xff1f;Hitboxer是一款专业的SOCD按键重映射工…...

Linux密钥文件管理排查方法

Linux密钥文件管理排查方法本文面向具备一定 Linux 基础的技术人员&#xff0c;围绕密钥文件管理展开&#xff0c;重点讨论敏感文件权限、轮换流程和审计追踪。在中级运维和系统管理工作中&#xff0c;这类主题常常与配置变更、资源状态、权限边界、自动化任务和业务影响交织在…...

Office Custom UI Editor:终极指南:如何彻底改造你的Office工作界面?

Office Custom UI Editor&#xff1a;终极指南&#xff1a;如何彻底改造你的Office工作界面&#xff1f; 【免费下载链接】office-custom-ui-editor Standalone tool to edit custom UI part of Office open document file format 项目地址: https://gitcode.com/gh_mirrors/…...

你的嵌入式数据记录仪方案:基于STM32CubeMX+FATFS+SD卡存储传感器数据(CSV格式实战)

嵌入式数据记录仪实战&#xff1a;STM32CubeMXFATFSSD卡构建工业级CSV存储方案 在工业物联网和智能硬件开发中&#xff0c;可靠的数据记录功能往往是产品核心价值所在。想象一下温室大棚的环境监控系统需要连续记录温湿度数据三个月&#xff0c;或者电力设备振动监测装置要在无…...

从FFT到CZT:解锁频谱细化的精准分析新维度

1. 为什么我们需要频谱细化&#xff1f; 在信号处理的世界里&#xff0c;傅里叶变换&#xff08;FFT&#xff09;就像是一把瑞士军刀&#xff0c;几乎每个工程师都会用它来分析信号的频率成分。但当你面对两个频率非常接近的信号时&#xff0c;FFT就显得力不从心了。我曾在一次…...

MLX90614红外测温传感器:从原理到Arduino实战应用指南

1. 项目概述&#xff1a;从接触式到非接触式的测温革新在嵌入式开发和物联网项目中&#xff0c;温度测量是一个永恒的主题。从传统的热敏电阻、DS18B20&#xff0c;到热电偶&#xff0c;我们习惯了将探头紧贴甚至刺入被测物体来获取读数。但你是否遇到过这样的困境&#xff1a;…...

TVA智能体范式的工业视觉革命(10)

重磅预告&#xff1a;本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容&#xff0c;该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著&#xff0c;特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...

Uniapp中处理加密PDF流:从字节数组到本地渲染的完整实践

1. 加密PDF流处理的核心挑战 在Uniapp中处理加密PDF流时&#xff0c;开发者常会遇到几个典型问题。首先是字节流格式混乱&#xff0c;后端可能返回分段加密的二进制数据&#xff0c;前端需要识别数据头标识&#xff08;如%PDF-1.7&#xff09;来判断完整性。我曾遇到一个案例&a…...

NotebookLM智能摘要失效真相(92%用户正在误用的3类文档结构)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;NotebookLM智能摘要失效的底层归因 NotebookLM 的智能摘要功能在部分场景下出现静默失效&#xff08;即无报错但输出空摘要或重复原文&#xff09;&#xff0c;其根本原因并非模型能力退化&#xff0c;…...

从U-net到U-net++:探索跳跃连接的演进与优化

1. U-net的跳跃连接&#xff1a;从基础原理到核心价值 我第一次接触U-net是在处理医学影像分割项目时。当时试遍了各种模型&#xff0c;直到发现这个结构简洁却效果惊人的网络&#xff0c;才真正体会到跳跃连接&#xff08;Skip Connection&#xff09;的魔力。简单来说&#x…...