Java单元测试及常用语句 | 京东物流技术团队

news2024/11/17 22:28:13

1 前言

编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中, 我们也可以对自己的代码进行一个二次检查。

以下是我总结的一些编写单元测试的好处:

1.测试代码逻辑时,不需要启动整个应用。

2.单元测试可以覆盖边界值

3.提高原有代码的复用

4.可以有效避免代码改动后,对原有逻辑的潜在影响

2 准备环境

Mockito是目前最普遍的单元测试模拟框架。Mockito可以模拟应用中依赖的复杂对象,从而把测试对象和依赖对象隔离开。PowerMock为Mockito提供了扩展功能。为模拟静态方法,final类,和私有方法等。我们选择使用以Mockito为主,PowerMock为辅的框架来做单元测试。

2.1 引入Mockito和PowerMock包,在pom.xml文件中加入以下依赖:

<properties>
    <powermock.version>2.0.9</powermock.version>
</properties>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-core</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>

PowerMock目前最新版本为2.0.9【PowerMock链接】由于PowerMock包中已经包含了对应的Mockito和JUnit包,所以无需再单独引入。

3 一些常用的mock语句

3.1 模拟指定类的对象实例,用于模拟依赖对象(类成员)

在Spring中,这些成员对象通过@Autowire,@Resource,@Value等方式注入,可能涉及到环境配置或者依赖第三方接口。在单元测试中,不是我们关注的点,所以可以用mock模拟

//方法一
Mockito.mock(OrderInfo.class);
//方法二
@Mock
private OrderInfo orderInfo;


@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}

3.2 定义被测试对象

把被测试服务类进行实例化

@InjectMocks
private OrderServiceImpl orderService;

3.3 模拟枚举类型/静态方法

需要把对应的模拟类放在@PrepareForTest中

//必须添加@RunWith和@PrepareForTest在类前
@RunWith(PowerMockRunner.class)
@PrepareForTest(OrderTypeEnum.class)


//在@Before中添加枚举mock
@Before
public void beforeTest() {
    mockStatic(OrderTypeEnum.class);
}

3.4 模拟依赖方法

在模拟完依赖的参数和返回值后,可以利用Mockito功能,进行依赖方法的模拟。如果模拟对象还有方法调用,则需要模拟这些依赖对象的方法。

/***
when.thenReturn 和 doReturn.when是两种实现方式
只有在使用@Spy时才会有区别
参考链接:https://www.imooc.com/wenda/detail/594190#id_653606
***/


//模拟枚举的方法调用
when(OrderTypeEnum.getByValue(anyInt())).thenReturn(100);
//模拟依赖对象的依赖方法调用
doReturn(resultInfoDTO).when(orderInfoService).getLastOrderInfo(orderInfoDTO);

3.5 模拟构造方法

PowerMock提供了对构造方法的模拟,但是需要把构造方法的类放在@PrepareForTest中

//必须在@PrepareForTest中添加对应类
@PrepareForTest({OrderTypeEnum.class, OrderServiceImpl.class})
whenNew(OrderInfoDTO.class).withNoArguments().thenReturn(orderInfoDTO);

3.6 验证方法调用次数

被测方法调用后,一些方法会出现调用多次或根据不同条件进行不同次数的调用。此时,可以根据验证方法调用次数,确定代码的有效性

verify(orderInfoService,times(1)).getLastOrderInfo(orderInfoDTO);

3.7 验证返回值

对于方法调用后的出参,我们会有一定的预期。所以,可以根据校验返回值是否符合预期,确保返回值的正确性

Assert.assertEquals(result, "123");

3.8 验证异常对象

JUnit的@Test注解提供了一个expected属性,可以指定一个期望的异常类型,用于捕获异常并验证其异常类型。【注】:只能验证异常类型,不能验证异常信息。

@Test(expected = BPLException.class)

4 单测举例

下面是一个本地方法的单元测试用例,方法中调用了外部接口,并且其中包含了枚举值的使用。

源方法即需要单测方法:

首先,是单元测试时一些必要的初始化

4.1 单测场景一(确定接口调用,并返回值正确):

通过verify方法来确定接口是否调用过,并且只调用过1次。

通过assert来确认返回值是否满足预期

4.2 单测场景二(必要异常是否抛出):

通过在@Test注解上加入expected属性,测试当接口返回值为空时,是否可以抛出异常

4 总结

编写单元测试在开发中的地位举足轻重。在开发过程中,避免不了优化或重构历史代码。单元测试,在一定程度上可以帮助测试更新后逻辑,以及潜在调用链。另外也分享一些链接,希望可以帮助大家完成从0到1的搭建。

5 参考资料

  • Java编程技巧之单元测试用例编写流程:https://mp.weixin.qq.com/s/hX_RIYs-nBnqVwdq5B4rhg
  • powerMock的Git链接:https://github.com/powermock/powermock
  • powerMock简介:https://www.baeldung.com/intro-to-powermock
  • 避免Install的时候Skip test: https://maven.apache.org/plugins-archives/maven-surefire-plugin-2.12.4/examples/skipping-test.html

作者:京东物流 牟佳义

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

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

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

相关文章

stm32CubeMX HAL W5500芯片介绍 第一章

W5500芯片介绍 文章目录 W5500芯片介绍简单简绍以太网以太网分五层&#xff1a;第一层物理层&#xff1a;第二层&#xff1a;数据链路层&#xff1a;第三层&#xff1a;网络层&#xff1a;第四层&#xff1a;传输层&#xff1a;第五层&#xff1a;应用层&#xff1a;以太网应用…

redis面试题二

redis如何处理已过期的元素 常见的过期策略 定时删除&#xff1a;给每个键值设置一个定时删除的事件&#xff0c;比如有一个key值今天5点过期&#xff0c;那么设置一个事件5点钟去执行&#xff0c;把它数据给删除掉&#xff08;优点&#xff1a;可以及时利用内存及时清除无效数…

《存储IO路径》专题:IO块设备的创建

今天我们来一起学习一下Linux块设备层。它就像是一位大厨&#xff0c;为我们准备各种数据的饕餮盛宴。这个大厨非常厉害&#xff0c;不仅能够读取和写入数据&#xff0c;还能对数据进行各种复杂的操作&#xff0c;比如切割、合并、复制等等。那么&#xff0c;块设备层是如何实现…

C#-抽象类与接口

文章目录 一、抽象类和接口总结总结补充说明主要区别 二、抽象类2.1 抽象类概述与声明2.2 抽象方法2.3 抽象类与抽象方法的使用 三、接口3.1 接口概述概述特征声明示例 3.2 接口的实现和继承说明示例 3.3 显式接口成员实现说明注意示例 一、抽象类和接口总结 总结 抽象类和接…

k8s使用ECK(2.4)形式部署elasticsearch+kibana-http协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备elasticsearch-cluster.yaml二、部署并测试总结 前言 之前写了eck2.4部署eskibana&#xff0c;默认的话是https协议的&#xff0c;这里写一个使用http…

【docker】docker的一些常用命令-------从小白到大神之路之学习运维第92天

目录 一、安装docker-ce 1、从阿里云下载docker-cer.epo源 2、下载部分依赖 3、安装docker 二、启用docker 1、启动docker和不启动查看docker version 2、启动服务查看docker version 有什么区别&#xff1f;看到了吗&#xff1f; 3、看看docker启动后的镜像仓库都有什…

解密Spring MVC异常处理:从局部到全局,打造稳固系统的关键步骤

&#x1f600;前言 在现代软件开发中&#xff0c;异常处理是不可或缺的一部分&#xff0c;它能够有效地提高系统的稳定性和健壮性。在Spring MVC框架中&#xff0c;异常处理机制起着至关重要的作用&#xff0c;它允许开发者在程序运行过程中捕获、处理和报告异常&#xff0c;从…

26 Linux高级篇-Linux面试题

26 Linux高级篇-Linux面试题 文章目录 26 Linux高级篇-Linux面试题1.分析日志t.txt(访问量)&#xff0c;将各个ip地址截取&#xff0c;并统计出现次数&#xff0c;并按从大到小排序(腾讯)2.统计连接到服务器的各个ip情况&#xff0c;并按连接数从大到小排序(腾讯)3.如忘记了mys…

历时3天的springboot+vue打包成jar包

有人说问什么打包花了三天&#xff0c;里面的坑很多&#xff0c;我就先不叙述太多&#xff0c;直接说我搞了三天得出来的最后解决方案&#xff0c;不一定适合每一个人&#xff01;! # 前端 # 修改prod.env.js文件下的内容&#xff0c;把里面的 BASE_API 修改为和dev.env.js文件…

[管理与领导-63]:IT基层管理者 - 潜技能 - 1 - 职场中的陷阱 - 看清楚职场中的霸凌现象

目录 前言&#xff1a; 1&#xff1a;打击自尊心 2&#xff1a;孤立他人 3&#xff1a;恶意针对 4&#xff1a;当众羞辱 5&#xff1a;持续性否定 前言&#xff1a; 职场中&#xff0c;什么样的人都有。 害人之心不可有&#xff0c;防人之心不可无。 前者教人从善&…

顺序栈(数组形式)的实现

&#x1f308;什么是栈&#xff1f; 1.抽象化具象&#xff1a;可以理解为一个细长的乒乓球筒&#xff0c;一端封闭&#xff0c;放球只能从另一端放入球&#xff0c;取出球时也只能从该端取出。先进的球最后出&#xff0c;后进的球最先出。 2.定义&#xff1a;栈是一种线性数据…

【C++】map/multimap容器

1.map基本概念 2.map构造和赋值 #include <iostream> using namespace std;//map容器 构造和赋值 #include<map>//遍历输出map容器 void printMap(const map<int, int>& m) {for (map<int, int>::const_iterator it m.begin(); it ! m.end(); it)…

Ubuntu学习---跟着绍发学linux课程记录(第一部分)

文章目录 1、启动、关闭、挂起、恢复&#xff08;电源&#xff09;2、更多虚拟机操作2.1 电源设置2.2 硬件参数设置2.3 状态栏2.4 全屏显示 3、快照与系统恢复4、桌面环境5、文件系统6、用户目录7、创建目录和文件8、命令行&#xff1a;文件列表ls 9、命令行&#xff1a;切换目…

分布式任务调度框架

分布式任务调度框架 学习为主 文章目录 分布式任务调度框架一、概念二、架构图三、任务调度的流程定时触发任务是如何实现的&#xff1f;&#xff1a;使用时间轮实现定时执行任务逻辑:3.1 对到达now时间后的任务&#xff08;超出now 5秒外)3.2 对到达now时间后的任务&#xff0…

从代码设计看 Glide 之生命周期(上)

欢迎关注我的其他平台账号&#xff1a; 掘金&#xff1a;0xforee 个人博客&#xff1a;0xforee’s blog 微信公众号&#xff1a; 上期我们探索了一个具备核心功能的图片加载库该怎么设计。这一期我们来看看如何给这个图片加载库关联生命周期管理。 欢迎关注本系列其他文章&…

PPPoE连接无法建立的排查和修复

嗨&#xff0c;亲爱的读者朋友们&#xff01;你是否曾经遇到过PPPoE连接无法建立的问题&#xff1f;今天我将为你详细解析排查和修复这个问题的步骤。 检查物理连接 首先&#xff0c;我们需要确保物理连接没有问题。请按照以下步骤进行检查&#xff1a; - 检查网线是否插好&…

vue训练场练习props和$emit,实现大写输入,小写输出。

场景&#xff1a; 在vue官网训练场&#xff0c;使用训练场中的组件。 仅作为练习笔记&#xff0c;仅供产考。 App.vue 组件代码 方式一&#xff1a;Watch监听 方式二&#xff1a;input绑定

安卓系列机型--软扩容“system分区扩容”操作步骤解析 增加系统分区大小

感兴趣的友友要区别扩容的概念。软扩容与硬扩容。硬扩容指拆解手机字库。更换大容量的字库来达到硬扩容。例如864硬扩容为8256等等。所谓的软扩容指的是将系统默认的系统分区大小修改分区表增大分区。例如原来系统分区默认2G。修改分区表为3G大小。意义在于可以刷写有些需要扩容…

ssm+vue“魅力”繁峙宣传网站源码和论文

ssmvue“魅力”繁峙宣传网站源码和论文102 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身…

CH341 USB总线转接芯片

产品概述&#xff1a; CH341是一个USB总线的转接芯片&#xff0c;通过USB总线提供异步串口、打印口、并口以及常用的2线和4线等同步串行接口。 在异步串口方式下&#xff0c;CH341提供串口发送使能、串口接收就绪等交互式的速率控制信号以及常用的MODEM联络信号&#xff0c;用于…