快速掌握JUnit等测试框架的使用,进行Java单元测试

1. 单元测试简介

单元测试(Unit Testing)是一种软件测试方法,通过对软件中的最小可测试单元进行验证,确保它们按预期工作。单元测试通常用于测试一个类的单个方法,以确保其逻辑正确、边界情况处理妥当、异常处理合适。单元测试的主要目标是提高代码质量,减少错误,并提高代码的可维护性和可测试性。

2. JUnit简介

JUnit是Java平台上最流行的单元测试框架之一。JUnit提供了一套丰富的注解和断言方法,方便开发者编写和执行单元测试。JUnit的核心概念包括测试类、测试方法、断言和注解。

3. 安装和设置JUnit

3.1 Maven项目

如果你使用Maven构建项目,可以在pom.xml文件中添加JUnit依赖:

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.7.0</version><scope>test</scope>
</dependency>
3.2 Gradle项目

如果你使用Gradle构建项目,可以在build.gradle文件中添加JUnit依赖:

testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0'

4. JUnit 5基础用法

4.1 基本注解
  • @Test:标识一个测试方法。
  • @BeforeEach:在每个测试方法执行前执行。
  • @AfterEach:在每个测试方法执行后执行。
  • @BeforeAll:在所有测试方法执行前执行,仅运行一次。
  • @AfterAll:在所有测试方法执行后执行,仅运行一次。
4.2 编写简单测试

下面是一个简单的测试示例,展示了如何使用JUnit 5进行单元测试。

import org.junit.jupiter.api.*;import static org.junit.jupiter.api.Assertions.*;public class CalculatorTest {private Calculator calculator;@BeforeEachpublic void setUp() {calculator = new Calculator();}@Testpublic void testAdd() {int result = calculator.add(2, 3);assertEquals(5, result, "2 + 3 should equal 5");}@Testpublic void testSubtract() {int result = calculator.subtract(5, 3);assertEquals(2, result, "5 - 3 should equal 2");}@AfterEachpublic void tearDown() {calculator = null;}
}

在这个示例中,CalculatorTest类包含两个测试方法testAddtestSubtract,分别测试Calculator类的addsubtract方法。@BeforeEach注解的方法在每个测试方法执行前运行,以初始化测试环境。

5. JUnit断言

JUnit提供了一组丰富的断言方法,用于验证测试结果。常用的断言方法包括:

  • assertEquals(expected, actual):验证两个值是否相等。
  • assertNotEquals(unexpected, actual):验证两个值是否不等。
  • assertTrue(condition):验证条件是否为真。
  • assertFalse(condition):验证条件是否为假。
  • assertNull(object):验证对象是否为null。
  • assertNotNull(object):验证对象是否不为null。
  • assertThrows(expectedType, executable):验证执行的代码是否抛出指定的异常。
@Test
public void testAssertions() {// 断言两个值相等assertEquals(4, 2 + 2);// 断言条件为真assertTrue(5 > 3);// 断言对象不为空assertNotNull(new Object());// 断言抛出指定异常assertThrows(ArithmeticException.class, () -> {int result = 1 / 0;});
}

6. 参数化测试

参数化测试允许使用不同的参数多次运行同一个测试方法。JUnit 5提供了@ParameterizedTest注解和一些参数源注解,如@ValueSource@CsvSource等,用于实现参数化测试。

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;import static org.junit.jupiter.api.Assertions.*;public class ParameterizedTestExample {@ParameterizedTest@ValueSource(ints = {1, 2, 3, 4, 5})public void testIsPositive(int number) {assertTrue(number > 0, "Number should be positive");}
}

在这个示例中,testIsPositive方法使用不同的参数(1到5)运行多次,以验证每个参数都大于0。

7. 测试生命周期

测试生命周期注解用于在测试方法执行前后进行一些准备和清理工作。

  • @BeforeEach:在每个测试方法执行前运行。
  • @AfterEach:在每个测试方法执行后运行。
  • @BeforeAll:在所有测试方法执行前运行,仅运行一次。
  • @AfterAll:在所有测试方法执行后运行,仅运行一次。
import org.junit.jupiter.api.*;public class LifecycleTest {@BeforeAllpublic static void initAll() {System.out.println("Before all tests");}@BeforeEachpublic void init() {System.out.println("Before each test");}@Testpublic void testOne() {System.out.println("Test one");}@Testpublic void testTwo() {System.out.println("Test two");}@AfterEachpublic void tearDown() {System.out.println("After each test");}@AfterAllpublic static void tearDownAll() {System.out.println("After all tests");}
}

运行上述代码时,输出将显示测试生命周期的执行顺序。

8. 测试异常和超时

在测试中,验证方法是否正确处理异常和超时情况非常重要。

8.1 测试异常

可以使用assertThrows方法验证方法是否抛出指定的异常。

@Test
public void testException() {Exception exception = assertThrows(ArithmeticException.class, () -> {int result = 1 / 0;});assertEquals("/ by zero", exception.getMessage());
}
8.2 测试超时

可以使用@Timeout注解设置测试方法的执行时间限制。

import org.junit.jupiter.api.Timeout;import java.time.Duration;@Test
@Timeout(1)  // 单位为秒
public void testTimeout() throws InterruptedException {Thread.sleep(500);  // 模拟一些耗时操作
}

如果测试方法在指定时间内没有完成,将会失败。

9. Mocking

在单元测试中,有时需要模拟(mock)对象的行为,以便在不依赖真实对象的情况下进行测试。Mockito是一个流行的Java mocking框架。

9.1 引入Mockito依赖

在Maven项目中添加Mockito依赖:

<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.7.7</version><scope>test</scope>
</dependency>

在Gradle项目中添加Mockito依赖:

testImplementation 'org.mockito:mockito-core:3.7.7'
9.2 使用Mockito进行Mocking

下面是一个使用Mockito的示例:

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;public class MockitoExampleTest {@Mockprivate Calculator calculator;@InjectMocksprivate CalculatorService calculatorService;public MockitoExampleTest() {MockitoAnnotations.initMocks(this);}@Testpublic void testAdd() {when(calculator.add(2, 3)).thenReturn(5);int result = calculatorService.add(2, 3);assertEquals(5, result);verify(calculator).add(2, 3);}
}

在这个示例中,我们使用@Mock注解创建一个Calculator的mock对象,并使用@InjectMocks注解将其注入到CalculatorService中。when方法用于定义mock对象的行为,verify方法用于验证mock对象的交互。

10. 集成测试

虽然单元测试主要用于验证单个类或方法的功能,但集成测试则用于验证多个组件之间的交互。JUnit也可以用于编写集成测试。

10.1 使用Spring进行集成测试

Spring框架提供了强大的测试支持,使得编写和执行集成测试变得更加简单。通过@SpringBootTest注解,我们可以启动Spring应用上下文并进行测试。

添加Spring测试依赖(如果使用Maven):

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

使用Spring进行集成测试的示例:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
public class CalculatorServiceIntegrationTest {@Autowiredprivate CalculatorService calculatorService;@MockBeanprivate Calculator calculator;@Testpublic void testAdd() {when(calculator.add(2, 3)).thenReturn(5);int result = calculatorService.add(2, 3);assertEquals(5, result);}
}

在这个示例中,我们使用@SpringBootTest注解来启动Spring应用上下文,并使用@MockBean注解创建一个mock对象。在测试方法中,我们定义了mock对象的行为并验证了服务层的逻辑。

11. 代码覆盖率

代码覆盖率是衡量测试完整性的重要指标。它显示了测试覆盖了多少代码,可以帮助我们找出未被测试的代码部分。

11.1 使用JaCoCo

JaCoCo是一个流行的Java代码覆盖率工具。它可以与Maven和Gradle集成,用于生成代码覆盖率报告。

在Maven项目中添加JaCoCo插件:

<build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.6</version><executions><execution><goals><goal>prepare-agent</goal></goals></execution><execution><id>report</id><phase>prepare-package</phase><goals><goal>report</goal></goals></execution></executions></plugin></plugins>
</build>

运行Maven命令生成代码覆盖率报告:

mvn clean test
mvn jacoco:report

在Gradle项目中应用JaCoCo插件:

plugins {id 'jacoco'
}jacoco {toolVersion = "0.8.6"
}test {useJUnitPlatform()finalizedBy jacocoTestReport
}jacocoTestReport {reports {xml.required = truehtml.required = true}
}

运行Gradle命令生成代码覆盖率报告:

./gradlew test jacocoTestReport

生成的报告将显示哪些代码被测试覆盖,哪些代码没有覆盖。

12. 测试最佳实践

12.1 保持测试独立

每个测试方法应该是独立的,不应该依赖其他测试方法的执行结果。这样可以确保每个测试都能单独运行,并且容易调试和维护。

12.2 使用有意义的测试名称

测试方法的名称应该清晰地描述测试的目的和预期行为。这样可以使测试代码更加可读,并且在测试失败时可以更容易地理解问题所在。

12.3 测试边界情况

在编写单元测试时,不仅要测试正常的输入,还要测试边界情况和异常情况。这可以确保代码在各种情况下都能正常工作。

12.4 避免使用静态变量

在单元测试中使用静态变量可能会导致测试之间的相互影响,从而引入难以调试的问题。尽量避免在测试代码中使用静态变量。

12.5 定期运行测试

定期运行测试可以帮助及时发现代码中的问题,特别是在进行代码重构或添加新功能时。持续集成(CI)系统可以自动化运行测试,并生成测试报告。

单元测试是软件开发过程中至关重要的一部分。它通过验证最小的可测试单元,确保代码的正确性和稳定性。JUnit作为Java平台上最流行的单元测试框架,提供了丰富的注解和断言方法,方便开发者编写和执行单元测试。

此外,使用Mockito进行mocking、使用Spring进行集成测试、使用JaCoCo生成代码覆盖率报告等,都是提高测试质量和覆盖率的有效手段。通过遵循测试最佳实践,可以进一步提高测试代码的质量和可维护性。

黑马程序员免费预约咨询

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

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

相关文章

【HarmonyOS - UIAbility组件和UI的数据同步】

简述 基于HarmonyOS的应用模型&#xff0c;可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信&#xff1a;基于发布订阅模式来实现&#xff0c;事件需要先订阅后发布&#xff0c;订阅者收到消息后进行处理。使用globalThis进行数据同步…

unity 打包PC安装包中常见文件的功能

目录 前言 一、打包好的文件 二、常用文件 1.文件夹XXX_Data 2.文件夹MonoBleedingEdge 3.文件夹XXX_Data内部 三、文件的应用 1.如果你替换了一个图片 2.如果你新增了或减少了图片和资源 3.场景中有变动 4.resources代码加载的资源改了 5.如果你代码替换了 四、作…

Vue11-键盘事件

一、键盘事件&#xff1a;keydown和keyup事件 keydown 和 keyup 是两种常用于处理键盘输入事件的JavaScript事件。当你在网页的输入框或其他可输入元素上按下或释放键盘上的某个键时&#xff0c;这些事件就会被触发。 1-1、keydown 事件 当用户按下键盘上的某个键时&#xff…

vue3第三十九节(TS中的高级类型,分类以及使用注意事项)

前言&#xff1a;为什么需要使用高级类型&#xff0c;正常的类型不能满足日常的业务需求&#xff0c;对于复杂的数据结构、函数签名、类型转换&#xff0c;我们需要使用高级类型来处理&#xff0c;常用的高级类型包含以下几种&#xff1a; 常用的类型定义&#xff1a; 基本类…

【源码】html+JS实现:24小时折线进度图

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>24小时折线进度图</title> <st…

基于SpringBoot3+Vue3宠物小程序宠物医院小程序的设计与实现

大家好&#xff0c;我是程序员小孟。 最近开发了一个宠物的小程序&#xff0c;含有详细的文档、源码、项目非常的不错&#xff01; 一&#xff0c;系统的技术栈 二&#xff0c;项目的部署教程 前端部署包&#xff1a;npm i 启动程序&#xff1a;npm run dev 注意事项&…

qmt量化交易策略小白学习笔记第30期【qmt编程之获取行业概念数据--如何获取板块分类信息数据以及板块成分股数据】

qmt编程之获取行业概念数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取行业概念数…

uniapp地图选择位置

直接上代码 通过一个点击事件调用官方api即可调用 点击调用成功后显示如下 然后选择自己所需要的位置即可

RAM IP核配置

REVIEW 之前已经学习过&#xff1a; ROM:FPGA寄存器 Vivado IP核-CSDN博客 串口接收&#xff1a;Vivado 串口接收优化-CSDN博客 1. 今日摸鱼计划 RAM创建与测试 小梅哥视频&#xff1a; 21C_嵌入式块存储器RAM介绍_哔哩哔哩_bilibili 21D_嵌入式块存储器RAM实现和仿真_哔哩…

在不使用js在情况下只用css实现瀑布流效果

使用到的是grid 布局&#xff0c;需要注意的是grid-template-rows: masonry; 目前只有Firefox 浏览器支持这个效果&#xff0c;而且还是一个实验性属性需要在设置里面开发实验性选项才行。 实例 <!DOCTYPE html> <html> <head><title>Document</ti…

为CAP面板添加简单的Authentication登录验证功能 C#|.net

终于搞定了CAP Dashboard的登录验证功能! 因为网上找不到简单的CAP Dashboard的登录验证功能,所以这个功能摸索着开发了好久。 这个Authentication认证功能,不仅适用于CAP面板,也适用于懒得开发登录页面,但是又需要简单用户名密码登录的网页。 做过后端的比较熟悉,CAP面…

告别“人治”时代,物业运维平台能否成为行业新标准?

随着数字化时代的飞速发展&#xff0c;智能化、数字化已经遍及所有的行业。物业服务企业也不例外&#xff0c;你是否还在想象物业运维工作依旧停留在手动报修、纸质记录的古老时代&#xff1f;那么&#xff0c;你就OUT了&#xff0c;物业运维平台已经悄然崛起&#xff0c;正在以…

《Brave New Words 》2.2 阅读理解的未来,让文字生动起来!

Part II: Giving Voice to the Social Sciences 第二部分&#xff1a;为社会科学发声 The Future of Reading Comprehension, Where Literature Comes Alive! 阅读理解的未来&#xff0c;让文字生动起来&#xff01; Saanvi, a ninth grader in India who attends Khan World S…

鸿蒙轻内核A核源码分析系列七 进程管理 (2)

本文先熟悉下进程管理的文件kernel\base\core\los_process.c中的内部接口&#xff0c;读读代码&#xff0c;做些记录。 1、LiteOS-A内核进程全局变量 ⑴是进程池&#xff0c;存放各个进程控制块LosProcessCB的信息。⑵处开始的g_freeProcess是空闲进程链表&#xff0c;挂载各…

【机器学习】简答

1.什么是机器学习&#xff1f; 机器学习致力于研究如何通过计算的手段&#xff0c;利用经验来改善系统自身的性能。“训练”与“预测”是机器学习的两个过程&#xff0c;“模型”则是过程的中间输出结果&#xff0c;“训练”产生“模型”&#xff0c;“模型”指导 “预测”。计…

算法体系-20 第二十节暴力递归到动态规划

前言 动态规划模型从尝试暴力递归到傻缓存到动态规划 四种模型和体系班两种模型一共六种模型 0.1 从左往右模型 0.2 范围讨论模型范围尝试模型 &#xff08;这种模型特别在乎讨论开头如何如何 结尾如何如何&#xff09; 玩家博弈问题&#xff0c;玩家玩纸牌只能那左或者右 0.3 …

【DrissionPage】Linux上如何将https改为http

最近有个老板找我做一个自动化的程序&#xff0c;要求部署到Linux上 这是一个http协议的网站&#xff0c;chrome在默认设置下&#xff0c;会将http的网站识别成不安全的内容&#xff0c;然后自动将http转化成https访问 但是&#xff0c;这个http的网站它的加载项里既有http的…

HAL库--内存保护(MPU)实验

MPU是内核外设&#xff0c;想获取相关资料只能从内核手册查找 MPU功能仅F7/H7系列具备 内存保护单元(MPU介绍) MPU基本介绍 说白了MPU用来管理内存和外设存储区的访问权限 MPU可配置保护8/16个内存区域(看芯片型号)&#xff0c;每个区域最小要求256字节&#xff0c;且每个区…

STL入门指南:从容器到算法的完美结合

目录 ​编辑 一、什么是STL 二、STL的版本 三、STL的六大组件 1. 容器&#xff08;Containers&#xff09;&#xff1a; 2. 算法&#xff08;Algorithms&#xff09;&#xff1a; 3. 迭代器&#xff08;Iterators&#xff09;&#xff1a; 4. 仿函数&#xff08;Functo…

安鸾学院靶场——安全基础

文章目录 1、Burp抓包2、指纹识别3、压缩包解密4、Nginx整数溢出漏洞5、PHP代码基础6、linux基础命令7、Mysql数据库基础8、目录扫描9、端口扫描10、docker容器基础11、文件类型 1、Burp抓包 抓取http://47.100.220.113:8007/的返回包&#xff0c;可以拿到包含flag的txt文件。…