SpringBoot测试实践

测试按照粒度可分为3层:

  1. 单元测试:单元测试(Unit Testing)又称为模块测试 ,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
  2. 集成测试:整合测试(Integration Testing),又称组装测试,即对程序模块采用一次性或增值方式组装起来,对系统的接口进行正确性检验的测试工作。整合测试一般在单元测试之后、系统测试之前进行。实践表明,有时模块虽然可以单独工作,但是并不能保证组装起来也可以同时工作。该测试,可以由程序员或是软件品保工程师进行。
  3. 端到端测试:端到端测试(End To End Testing),又称系统测试。

在这里插入图片描述

通常需求开发后需要经过RD单测&自测后进行提测,提测往往需要达到一定的单测/自测代码覆盖率,或者某些基本case通过(冒烟测试),符合提测要求后QA对整体功能进行端到端测试。

完善的测试流程有助于提升代码质量和研发效率,这中间一方面对RD自身的业务素养有要求,另一方面对团队研发流程的规范性有要求。

成熟的研发流程和体系应减少“人性”带来的不稳定性,测试即是应对该不稳定性的有效方法之一。

本文记录了结合SpringBoot进行测试的一些案例,示例代码参见: spring-boot-test-sample

注意区分JUnit4和JUnit5的注解,本文代码基于JUnit4
{: .prompt-warning }

首先我们引入依赖:

<dependencies><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.6.13</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>2.28.2</version><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>2.28.2</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.2</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.2</version><scope>test</scope></dependency></dependencies></dependencyManagement>

Mockito & PowerMockito 单元测试

当我们仅仅需要验证代码逻辑,不需要Spring的bean注入时,使用Mockito & PowerMockito来快速测试。

Mockito用于mock对象便于对代码逻辑进行测试&验证,但Mockito mock的方法有限,无法mock final、private、static方法,而PowerMockito框架弥补了这一点。两者可以混合使用。

案例:


@RunWith(PowerMockRunner.class)
// mock static method
@PrepareOnlyThisForTest({SampleUtil.class})
@PowerMockIgnore({"javax.net.ssl.*","javax.management.*", "javax.security.*", "javax.crypto.*"})
public class UnitTest {@Mockprivate SampleRepository sampleRepository;@InjectMocksprivate SampleService sampleService;@BeforeClasspublic static void beforeAll(){System.out.print("\n\n\n++++++++++++++\n\n\n");}@AfterClasspublic static void afterAll(){System.out.print("\n\n\n==============\n\n\n");}@Beforepublic void before(){}@Afterpublic void after(){}@Testpublic void getSamples() throws JSONException {PowerMockito.mockStatic(SampleUtil.class);// 注意所有when内部的方法参数必须用org.mockito.ArgumentMatchers的方法包一层,不能直接传PowerMockito.when(SampleUtil.getSomething(eq("1"))) // 反例:.when(SampleUtil.getSomething("1")) .thenReturn(1L);PowerMockito.when(sampleRepository.selectSamples(argThat(id -> id.equals(1L)))).thenReturn(new ArrayList<>());PowerMockito.when(sampleRepository.selectSamples(argThat(new GreaterOrEqual<>(1L)))).thenReturn(new ArrayList<>());// 这里有any(),anyString()等// 如果参数是String,mock方法传入的是null,则mock不生效,传null需指定为any()Mockito.when(sampleRepository.selectSamples(any())).thenReturn(new ArrayList<>());// verify方法调用次数Mockito.verify(sampleRepository, Mockito.times(1)).selectSamples(any());// Mockito.verify(sampleRepository, Mockito.times(1)).selectSamples(argThat(i->i.equals(1)));// capture参数验证ArgumentCaptor<Long> paramCap = ArgumentCaptor.forClass(Long.class);Mockito.verify(sampleRepository, Mockito.times(1)).selectSamples(paramCap.capture());Assert.assertNotNull(paramCap.getValue());List<Sample> samples = sampleService.listSamples("1");// 如果sample.size()返回Long,需要加一个 sample.size().longValue()方法Assert.assertEquals(0,samples.size());// 比较JSONJSONAssert.assertEquals("{\"a\":1}","{\"a\":1}",false);// 解析JSONAssert.assertEquals(JsonPath.parse("{\"a\":1}").read("$.a").getClass(),Integer.class);}@Testpublic void mockPrivate() {try {Method method = PowerMockito.method(Sample.class, "privateMethodName", Long.class);method.invoke(sampleService, 0L);Assert.fail();} catch (Exception e) {Assert.assertEquals("报错信息", e.getCause().getMessage());}}}

@Mock和@MockBean使用格式:Mockito.when(localVar.method()).thenXxx…

@Spy和@SpyBean使用格式:Mockito.doXxx().when(localVar).method()

Spring 测试

当依赖Spring时,可以利用Spring和PowerMockito一起完成mock和test

案例:

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@PrepareOnlyThisForTest({SampleUtil.class})
@ContextConfiguration(classes = ControllerSliceTestWithPowerMockito.Context.class)
public class ControllerSliceTestWithPowerMockito {// @Import加入需要扫描的Bean// @Configuration配合其他都行,参考@ContextConfiguration注释@Import(SampleController.class)static class Context {}@MockBeanprivate SampleService sampleService;@SpyBeanprivate SampleConverter sampleConverter;@Testpublic void zkSetup() {PowerMockito.mockStatic(SampleUtil.class);PowerMockito.when(SampleUtil.getSomething(eq("a"))).thenReturn(1L);sampleConverter.test();// assert, verify}}

WebMvc 切片测试

  • @AutoConfigureWebMvc : Use this if you need to configure the web layer for testing but don’t need to use MockMvc
  • @AutoConfigureMockMvc : Use this when you just want to configure MockMvc
  • @WebMvcTest : Includes both the @AutoConfigureWebMvc and the @AutoConfigureMockMvc, among other functionality.

三者区别,参考:What’s the difference between @AutoConfigureWebMvc and @AutoConfigureMockMvc?

案例一:

@WebMvcTest(SampleController.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestSampleController.TestContext.class)
public class TestSampleController {private static final Logger log = LoggerFactory.getLogger(TestSampleController.class);// 这里填入需要扫描的Bean,这样就不用扫描整个project文件,加快测试速度@Import({SampleController.class, ControllerExceptionAdvice.class})@Configuration // 这里兼容老版本,高版本不用加static class TestContext {}@Autowiredprivate MockMvc mockMvc;@MockBeanprivate SampleService sampleService;// 这里用SpyBean注解:当SampleController中用到了SampleConverter,但是又不需要mock,得用converter原本的逻辑// 或用@MockBean时,在 Mockito.when(...).thenCallRealMethod()就行。@SpyBeanprivate SampleConverter sampleConverter;@Beforepublic void prepareMock() {// 对SampleController中调用了的SampleService的方法进行mockMockito.doNothing().when(sampleService).sampleMethod(Mockito.any());}@Testpublic void shouldReturnSuccess() throws Exception {SampleRequest req = new SampleRequest();req.setA(1L);String bodyJson = JsonUtils.toJson(req);mockMvc.perform(MockMvcRequestBuilders.post("/test").contentType(MediaType.APPLICATION_JSON).content(bodyJson)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(MockMvcResultMatchers.content().json("{\"success\":true}"));}@Testpublic void shouldReturnErrorMsg() throws Exception {SampleRequest req = new SampleRequest();req.setBString bodyJson = JsonUtils.toJson(req);mockMvc.perform(MockMvcRequestBuilders.post("/test2").contentType(MediaType.APPLICATION_JSON).content(bodyJson)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(MockMvcResultMatchers.content().json("{\"success\":false,\"errorMsg\":\"错误信息\"}"));}
}

案例二:


@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("com.dianping.cat.Cat")
// mock static method
@PrepareForTest({SampleUtil.class})
// spring bean
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@PowerMockIgnore({"javax.net.ssl.*","javax.management.*", "javax.security.*", "javax.crypto.*"})
// @SpringBootTest从当前包向上找@SpringBootConfiguration,或者指定
@SpringBootTest(classes = SpringTestCommonConfig.class)
public class SpringBeanTest {// 这个mock对象会注入Spring容器@MockBeanprivate SampleRepository sampleRepository1;// 真实调用该对象逻辑@SpyBeanprivate SampleRepository sampleRepository2;@Autowiredprivate SampleRepository sampleRepository3;@Autowiredprivate ApplicationContext applicationContext;@Autowiredprivate SampleConfig sampleConfig;@Testpublic void sampleBeanTest() throws JSONException {SampleRepository bean = applicationContext.getBean(SampleRepository.class);Assert.assertEquals(sampleRepository1,bean);}}

此外我们使用h2内存数据库达到对Mapper的测试,也有testcontainers库推出用于测试与外部系统的交互,这里不赘述,详见示例代码

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

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

相关文章

【自动驾驶】ROS小车系统、运动底盘的运动学分析和串口通信控制

文章目录 小车组成轮式运动底盘的组成轮式运动底盘的分类轮式机器人的控制方式感知传感器ROS决策主控ROS介绍ROS的坐标系ROS的单位机器人电气连接变压模块运动底盘的电气连接ROS主控与传感器的电气连接ROS主控和STM32控制器两种控制器的功能运动底盘基本组成电池电机控制器与驱…

AI视频教程下载-用LangChain 开发 OpenAI、 LLAMA 、 Gemini 等AI应用

LangChain MasterClass- OpenAI LLAMA 2 GPT LLM Apps__ Python&#xff08;LangChain MasterClass-Develop 7 OpenAI LLM Apps using Python&#xff09; 探索LangChain、Pinecone、OpenAI、LLAMA 2及Google Gemini Pro LLM在现实世界中的应用。构建AI应用——拥抱脸&#xff…

写一个可以批量修改图片分辨率的工具

说在前面 &#x1f388;在视觉内容至关重要的今天&#xff0c;图片尺寸的调整对于网站加载速度和用户体验有着直接影响。本文介绍的Node.js工具&#xff0c;通过简单的命令行操作&#xff0c;允许用户批量调整图片尺寸&#xff0c;支持单张图片和整个目录的操作&#xff0c;提供…

【机器学习】---无监督学习

引言 在机器学习的广阔领域中&#xff0c;无监督学习扮演着至关重要的角色。不同于有监督学习&#xff0c;无监督学习处理的是没有标签的数据集&#xff0c;即我们不知道每个数据点的正确答案或分类。然而&#xff0c;这并不意味着无监督学习无法为我们提供有价值的信息。相反…

AI音乐:创新引擎还是创意终结者?

✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点赞、关注、收藏、评论&#xff0c;是对我最大…

学生管理系统更新(账号系统)

展示 头文件 #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//输入输出函数 #include<stdlib.h>//动态分配函数和随机函数 #include<windows.h>//控制台程序&#xff0c;用来实现cmd指令&#xff0c;title指令&#xff0c;cls指令等等 …

Ollama深度探索:AI大模型本地部署的全面教程

目录 引言一、Ollama概述1、定义与定位2、核心功能3、技术优势4、应用场景 二、安装与配置1、系统要求2、安装方法3、配置指南4、启动Ollama服务 四、快速开始1、启动Ollama2、部署运行模型3、REEST API 五、自定义模型1、定制化的必要性2、使用Modelfile定制模型3、参数调整4、…

IPSEC VPN

IPSEC VPN IPSEC是为IP网络提供安全性的协议和服务的集合,是一种协议簇&#xff0c;一个基于网络层&#xff0c;应用密码学的安全信息协议组。一开始TCP/IP 没有考虑到信息的安全传输。IPSEC协议簇诞生的意义就是保证TCP/IP的安全传输。 伪头部校验&#xff1a;TCP再校验的时…

升级到tomcat10和Java 21后,idea控制台system.out.println输出中文乱码问题

最近一次性从tomcat 9升级到tomcat 10&#xff0c;同时Java sdk也从1.8升级到21。 升级过程中&#xff0c;当然会遇到很多问题&#xff0c;但是控制台输出中文乱码问题&#xff0c;着实折腾了很久。 1、尝试各种方法 网上说的很多通用方法都试过了&#xff0c;就是不生效。包…

前端:Element UI 与 Vuetify 的选择

vuetify优势 1、多端适配&#xff0c;Vuetify完全按照Material设计规范进行开发&#xff0c;每一个组件都经过精心设计&#xff0c;具有模块化、响应式和优秀的性能。 使用独特和动态的 布局 自定义您的应用程序&#xff0c;并使用 SASS 变量 自定义您的组件的样式。只需要做下…

【CT】LeetCode手撕—236. 二叉树的最近公共祖先

目录 题目1- 思路2- 实现⭐236. 二叉树的最近公共祖先——题解思路 3- ACM实现 题目 原题连接&#xff1a;236. 二叉树的最近公共祖先 1- 思路 模式识别 模式1&#xff1a;二叉树最近公共祖先 ——> 递归 判断 递归思路&#xff0c;分情况判断&#xff1a; 1.参数及返…

香港“试水”医疗多模态大模型

更好地引入及发掘行业数据有望为垂直领域内的多模态大模型开发提供新可能。中国香港特区传统科研优势要嫁接产业风口&#xff0c;国际化渠道如何与内地资源携手&#xff1f; 产业多模态大模型“风头”正盛&#xff0c;在积极寻找经济新动能的中国香港特区&#xff0c;相关产业…

SQL新手蜕变:掌握这20条常用SQL语句,让你也能成为高手!

序言 在现代软件开发中&#xff0c;SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;作为与数据库交互的标准编程语言&#xff0c;是每个开发者必学的基础技能。掌握SQL并在数据库管理与数据分析中应用自如&#xff0c;能显著提升开发效率和数…

如何修复“AI的原罪”

如何修复“AI的原罪” 上个月&#xff0c;《纽约时报》声称&#xff0c;科技巨头OpenAI和谷歌不顾服务条款和版权法的禁止&#xff0c;将大量YouTube视频转录成文本&#xff0c;并将其用作人工智能模型的额外训练数据&#xff0c;从而进入了版权灰色地带。《纽约时报》还援引Me…

掌握JavaScript ES6精髓:探索函数和对象的高级扩展与实用技巧

序言 JavaScript&#xff0c;作为前端开发中不可或缺的语言&#xff0c;已经发展到了ECMAScript 2015&#xff08;简称ES6&#xff09;以及后续的版本。ES6带来了诸多语法上的改进和创新&#xff0c;使得代码更加简洁、优雅&#xff0c;同时也提供了更多的编程模式和实用技巧。…

【ONE·基础算法 || 记忆化搜索】

总言 主要内容&#xff1a;编程题举例&#xff0c;熟悉理解记忆化搜索类题型&#xff08;对比递归、动态规划理解运用&#xff09;。             文章目录 总言1、记忆化搜索1.1、基本介绍1.2、细节理解&#xff08;记忆搜索化、递归、动态规划……&#xff09; 2、斐…

idea插件开发之一起来开发个打印方法入参和返回值的插件吧!

写在前面 源码 。 在开发过程中为了调试代码我们就可能就需要知道某个方法入参的值是什么&#xff0c;或者是返回值是什么。此时&#xff0c;我们的解决办法一般都是debug&#xff0c;但是debug的效率说实话其实是不高的&#xff0c;特别是不断的调试&#xff0c;不断的debug。…

KT148A-SOP8语音芯片接收到一线串口指令到播放声音大概多长时间

一、问题简介 请问KT148A-SOP8语音芯片接收到一线串口指令&#xff0c;到播放出来声音&#xff0c;大概需要多长时间 我的需求是做按键提示音&#xff0c;初测了一下感觉有延时&#xff0c;这个要如何处理 详细说明 KT148A从接收到指令&#xff0c;到执行&#xff0c;到播放…

JavaScript基于时间的动画算法

前段时间无聊或有聊地做了几个移动端的HTML5游戏。放在不同的移动端平台上进行测试后有了诡异的发现&#xff0c;有些手机的动画会“快”一点&#xff0c;有些手机的动画会“慢”一点&#xff0c;有些慢得还不是一两点。 通过查找资料发现&#xff0c;基于帧的算法&#xff08…

多模态大模型时代下的文档图像智能分析与处理

0. 前言 随着人工智能技术的不断发展&#xff0c;尤其是深度学习技术的广泛应用&#xff0c;多模态数据处理和大模型训练已成为当下研究的热点之一&#xff0c;这些技术也为文档图像智能处理和分析领域带来了新的发展机遇。 多模态大模型时代下的文档图像智能分析与处理的研究…