【JUnit实战3_05】第二章:探索 JUnit 的核心功能(四) - 详解

news/2025/11/19 8:38:30/文章来源:https://www.cnblogs.com/gccbuaa/p/19240459

JUnit in Action, Third Edition

《JUnit in Action》全新第3版封面截图

写在前面
作为第二章 JUnit 功能特性扫盲篇的最后一篇自学笔记,我个人对这部分的定位是增长见识、拓宽眼界为主。很多知识点都给人眼前一亮的感觉:原来 JUnit 5 还能这样用!但是时间精力确实有限,不可能完全展开讨论,留下关键印象就显得特别重要了。诀窍在于,记牢典型案例的应用场景。

文章目录

    • 2.13 基于手动硬编码的字符串数组的参数化测试
    • 2.14 基于枚举类的参数化测试
    • 2.15 基于 CSV 文件的参数化测试
    • 2.16 动态测试
    • 2.17 Hamcrest 框架用法示例

2.13 基于手动硬编码的字符串数组的参数化测试

通过组合使用 @ParameterizedTest 注解和 @ValueSource 注解,可以自定义参数化测试用例的展示名称(默认将 strings 数组中的元素值作为各测试用例的子标题):

class ParameterizedWithValueSourceTest {
private WordCounter wordCounter = new WordCounter();
@ParameterizedTest
@ValueSource(strings = {"Check three parameters", "JUnit in Action"})
void testWordsInSentence(String sentence) {
assertEquals(3, wordCounter.countWords(sentence));
}
}

实测结果:

Fig2.7

2.14 基于枚举类的参数化测试

通过组合使用 @ParameterizedTest 注解和 @EnumSource 注解,可以自定义参数化测试用例的展示名称(能在枚举注解内设置筛选条件,这个特性让人眼前一亮):

import static org.junit.jupiter.params.provider.EnumSource.Mode.EXCLUDE;
class ParameterizedWithEnumSourceTest {
private WordCounter wordCounter = new WordCounter();
@ParameterizedTest
@EnumSource(Sentences.class)
void testWordsInSentence(Sentences sentence) {
assertEquals(3, wordCounter.countWords(sentence.value()));
}
@ParameterizedTest
@EnumSource(value = Sentences.class, names = {"JUNIT_IN_ACTION", "THREE_PARAMETERS"})
void testSelectedWordsInSentence(Sentences sentence) {
assertEquals(3, wordCounter.countWords(sentence.value()));
}
@ParameterizedTest
@EnumSource(value = Sentences.class, mode = EXCLUDE, names = {"THREE_PARAMETERS"})
void testExcludedWordsInSentence(Sentences sentence) {
assertEquals(3, wordCounter.countWords(sentence.value()));
}
enum Sentences {
JUNIT_IN_ACTION("JUnit in Action"),
SOME_PARAMETERS("Check some parameters"),
THREE_PARAMETERS("Check three parameters");
private final String sentence;
Sentences(String sentence) {
this.sentence = sentence;
}
public String value() {
return sentence;
}
}
}

实测结果:

Fig2.8

2.15 基于 CSV 文件的参数化测试

最让人意外的是 JUnit 5 还能通过 @CsvFileSource 注解直接解析 CSV 文件,并将解析结果以 方法参数的形式 注入参数化测试(例如示例代码中的 expectedsentence)。如果数据量较小,也可以用 @CsvSource 注解手动输入 CSV 格式的数据源。

这部分内容其实和上一篇的参数注入有所重叠,为了强调 JUnit 在文件解析方面的强大,这里单列出来以便日后复盘。查看 @CsvFileSource 注解的源码还可以了解更多配置项,如分隔符的设置等,这里就不展开了。

示例代码1:

class ParameterizedWithCsvFileSourceTest {
private WordCounter wordCounter = new WordCounter();
@ParameterizedTest
@CsvFileSource(resources = "/word_counter.csv")
void testWordsInSentence(int expected, String sentence) {
assertEquals(expected, wordCounter.countWords(sentence));
}
}

上述代码中,CSV 文件路径是相对测试的 CLASSPATH 而言的,即 src/test/resources/。运行结果:

Fig2.9

示例代码2:(手动录入数据源)

class ParameterizedWithCsvSourceTest {
private final WordCounter wordCounter = new WordCounter();
@ParameterizedTest(name = "Line {index}: [{0}] - {1}")
@CsvSource(value = {"2, Unit testing", "3, JUnit in Action", "4, Write solid Java code"})
@DisplayName(value = "should parse CSV file")
void testWordsInSentence(int expected, String sentence) {
assertEquals(expected, wordCounter.countWords(sentence));
}
}

运行结果:

Fig2.5

2.16 动态测试

利用工厂模式注解 @TestFactory 可以动态生成多个测试用例。需要注意的是,最核心的测试方法需要返回如下指定类型:

  • 一个 DynamicNode 型对象(DynamicNode 为抽象类,DynamicContainerDynamicTest 是其具体的实现类);
  • 一个 DynamicNode 型数组;
  • 一个基于 DynamicNodeStream 流;
  • 一个基于 DynamicNodeCollection 集合;
  • 一个基于 DynamicNodeIterable 可迭代对象;
  • 一个基于 DynamicNodeIterator 迭代器对象。

示例代码如下:

class DynamicTestsTest {
private PositiveNumberPredicate predicate = new PositiveNumberPredicate();
@BeforeAll
static void setUpClass() {
System.out.println("@BeforeAll method");
}
@AfterAll
static void tearDownClass() {
System.out.println("@AfterAll method");
}
@BeforeEach
void setUp() {
System.out.println("@BeforeEach method");
}
@AfterEach
void tearDown() {
System.out.println("@AfterEach method");
}
@TestFactory
Iterator<DynamicTest> positiveNumberPredicateTestCases() {return asList(dynamicTest("negative number", () -> {System.out.println("negative number ...");assertFalse(predicate.check(-1));}),dynamicTest("zero", () -> {System.out.println("zero ...");assertFalse(predicate.check(0));}),dynamicTest("positive number", () -> {System.out.println("positive number ...");assertTrue(predicate.check(1));})).iterator();}}

实测结果:

Fig2.10

可以看到,各生命周期注解仅对添加了 @TestFactory 工厂注解的外层方法本身生效,对工厂方法中动态生成的测试用例均无效。具体的测试用例行为,由动态测试的第二个参数,即传入的 Executable 型断言对象决定。

备忘:意外发现一个 IDEA 控制台输出的 Bug

实测发现,IntelliJ IDEA 中的控制台输出结果与期望的顺序不符,每次在 IDEA 中运行动态测试,@BeforeAll@AfterAll 注解的输出结果都在最末尾:

### snip ###
@BeforeEach method
negative number ...
zero ...
positive number ...
@AfterEach method
@BeforeAll method
@AfterAll method
Process finished with exit code 0

但在命令行中的就是正确的顺序:

> mvn test -Dtest=DynamicTestsTest
### snip ###
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.manning.junitbook.ch02.dynamic.DynamicTestsTest
@BeforeAll method
@BeforeEach method
negative number ...
zero ...
positive number ...
@AfterEach method
@AfterAll method
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.016 s - in com.manning.junitbook.ch02.dynamic.DynamicTestsTest
### snip ###

2.17 Hamcrest 框架用法示例

Hamcrest 辅助框架提供了更具声明式风格的测试断言方法和组合工具,可以让代码可读性更好,同时报错信息的提示更加友好。其中会大量涉及 Matcher 对象的组合应用(matcher 又称为 约束(constraints判定条件(predicates,相关概念源自 JavaC++Objective-CPythonPHP 等编程语言)。

对函数式编程感兴趣的朋友不妨多看看 Hamcrest 的源码,学习学习当中定义的各种辅助 Matcher 是如何构建一个相对完善的测试语义的。毕竟 Java 8 的函数式特性已经发布十余年了,我本人也在各类项目中有意尝试这些写法,但在构筑流畅的语义抽象层时经常遭遇巨大阻力,以致于很多项目后期运维难以为继,可读性和命名上的一致性都不强。究其原因,一是自身的英语素养还有待加强,二是可供参考的体例不多,三是社区对函数式编程的响应积极性并不高,尤其是在绝大多数中小公司都将代码重构当成增加项目综合成本的一大来源,这方面的刻意练习就更少了。

要启用 Hamcrest 也不难,先新增必要的 Maven 依赖:

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>

下面通过常规报错提示和 Hamcrest 提示的效果对比来演示具体用法(报错信息演示):

public class HamcrestListTest {
private List<String> values;@BeforeEachpublic void setUp() {values = new ArrayList<>();values.add("John");values.add("Michael");values.add("Edwin");}@Test@DisplayName("List without Hamcrest will intentionally fail to show how failing information is displayed")public void testListWithoutHamcrest() {assertEquals(3, values.size());assertTrue(values.contains("Oliver") || values.contains("Jack") || values.contains("Harry"));}@Test@DisplayName("List with Hamcrest will intentionally fail to show how failing information is displayed")public void testListWithHamcrest() {assertThat(values, hasSize(3));assertThat(values, hasItem(anyOf(equalTo("Oliver"),equalTo("Jack"),equalTo("Harry"))));assertThat("The list doesn't contain all the expected objects, in order",values,contains("Oliver", "Jack", "Harry"));assertThat("The list doesn't contain all the expected objects",values,containsInAnyOrder("Jack", "Harry", "Oliver"));}}

运行结果:

Fig2.11

常见的 Hamcrest 静态工厂方法:

工厂方法功能
anything匹配任意内容,常用于单纯提高可读性。
is仅用于提高语句的可读性
allof检查其中的条件是否都满足
anyOf检查包含的条件是否存在任意一个满足
not反转目标条件的语义
instanceOf检查某对象是否均为另一对象的实例
sameInstance测试对象的同一性
nullValuenotNullValue测试空值、非空值
hasProperty测试该 Java Bean 是否具有某个属性
hasEntryhasKeyhasValue测试目标 Map 是否包含指定的项、键或值
hasItemhasItems检测目标集合中是否存在某个或某些子项
closeTo
greaterThan
greaterThanOrEqualTo
lessThan
lessThanOrEqualTo
测试目标数值是否接近、
大于、
大于或等于、
小于、
小于或等于某个值
equalToIgnoringCase测试某字符串是否与另一字符串相等(忽略大小写)
equalToIgnoringWhiteSpace测试某字符串是否与另一字符串相等(忽略空白字符)
containsStringendsWithstartsWith测试某字符串是否包含指定字符串、或者以指定字符串开头或结尾

不难看到,这些声明式的工厂方法都是非常简洁有力的,几乎不需要额外的注释。或许这才是函数式编程的正确打开方式吧。

(第二章完)

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

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

相关文章

2025年比较好的手拧螺丝用户好评厂家排行

2025年比较好的手拧螺丝用户好评厂家排行行业背景与市场趋势手拧螺丝作为五金紧固件中的重要品类,在电子设备、家用电器、汽车制造、新能源等领域有着广泛应用。根据中国五金制品协会最新发布的《2024-2025中国紧固件…

2025年知名的网红小火车厂家最新权威推荐排行榜

2025年知名的网红小火车厂家最新权威推荐排行榜行业背景与市场趋势随着文旅产业的蓬勃发展,观光小火车作为景区特色交通工具和网红打卡项目,市场需求持续增长。据中国旅游装备协会最新数据显示,2024年我国观光小火车…

DataGrip2025.2.4 11月最新版 安装、授权、使用说明

DataGrip2025.2.4 11月最新版 安装、授权、使用说明2025-11-19亲测 支持最新版本2025.2.4 支持Windows、MAC、Linux一 安装 官网下载 : https://www.jetbrains.com/zh-cn/datagrip/ 根据提示安装 二 授权说明回复 《D…

linux c开发工具

在 Linux 系统中,C 语言开发工具和环境是开发高性能应用的重要组成部分。以下是一些常用的 C 开发工具和环境,适用于大多数 Linux 发行版(如 Ubuntu、Debian、CentOS、Fedora 等):一、C 编译器(编译器工具链) 1…

2025年比较好的网红小火车厂家最新TOP实力排行

2025年比较好的网红小火车厂家最新TOP实力排行行业背景与市场趋势随着文旅产业的蓬勃发展,网红小火车作为景区特色交通工具和打卡项目,市场需求持续增长。据《2024-2025年中国旅游装备制造业发展报告》显示,2024年我…

2025年如何高效安全地在软件外包强大的平台上接单

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年评价高的云桌面系统代理商哪家强

2025年云桌面系统代理商推荐:北京拓实科技有限公司专业实力获得市场认可北京拓实科技有限公司作为业内领先的IT基础设施服务商,在云桌面系统代理领域具有显著优势。公司自2002年成立以来,深耕企业信息化建设23年,积…

2025年评价高的景区轨道观光小火车热门厂家推荐榜单

2025年评价高的景区轨道观光小火车热门厂家推荐榜单行业背景与市场趋势随着国内旅游业的蓬勃发展,景区配套设施升级成为提升游客体验的重要环节。轨道观光小火车作为景区交通与游览体验的双重载体,近年来市场需求持续…

2025年评价高的成都活动房厕所市场热度榜

2025年评价高的成都活动房厕所市场热度榜 行业背景与市场趋势 近年来,随着城市化进程加快、临时建筑需求激增以及环保政策的推动,活动房厕所市场在成都及周边地区呈现显著增长。据《2024年中国集成房屋行业报告》显…

2025年知名的乳化液过滤机TOP品牌厂家排行榜

2025年知名的乳化液过滤机TOP品牌厂家排行榜行业背景与市场趋势乳化液过滤机作为工业制造领域的关键设备,在金属加工、汽车制造、航空航天等行业中扮演着不可或缺的角色。随着中国制造业向高质量发展转型,乳化液过滤…

2025年靠谱的成都二手活动房本地优选榜

2025年靠谱的成都二手活动房本地优选榜行业背景与市场趋势随着城市化进程加速和建筑行业转型升级,成都二手活动房市场近年来呈现稳定增长态势。据中国建筑金属结构协会2024年发布的《中国装配式建筑行业发展报告》显示…

宝塔更换默认PHP版本

查看当前php版本ls -l /usr/bin/php 更换版本ln -sf /www/server/php/80/bin/php /usr/bin/php

完整教程:发刊词:开启你的高效决策之旅(专栏目录)

完整教程:发刊词:开启你的高效决策之旅(专栏目录)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&qu…

linux c守护进程

在 Linux 中,守护进程(Daemon)是指在后台运行、不与用户交互的进程。它们通常通过 systemd、init(如 SysVinit)或 supervisord 等系统服务管理。 下面我将从 原理、创建方式、管理方式 和 常用工具 四个方面来解释…

linux c启动进程

在 Linux 中,启动一个 C 程序(即编译并运行一个 C 程序)通常涉及以下几个步骤:? 一、编译 C 程序 使用 gcc 编译器编译 .c 文件: gcc -o myprogram myprogram.c-o myprogram:指定输出文件名(如 myprogram)。 …

2025年比较好的小型过滤机TOP品牌厂家排行榜

2025年小型过滤机TOP品牌厂家排行榜:专业解析与采购指南 行业背景与市场趋势 随着环保法规的日益严格和工业精细化需求的提升,小型过滤机市场在2025年迎来了新一轮增长。据《中国环保设备行业白皮书(2025)》数据…

2025年靠谱的液压油滤油机厂家最新TOP实力排行

2025年靠谱的液压油滤油机厂家最新TOP实力排行行业背景与市场趋势液压油滤油机作为工业领域的关键设备,在机械制造、电力、冶金、化工等行业中扮演着不可或缺的角色。随着中国制造业的持续升级和环保要求的不断提高,…

2025年知名的小型滤油机TOP品牌厂家排行榜

2025年知名的小型滤油机TOP品牌厂家排行榜 行业背景与市场趋势 随着工业环保要求的日益严格,小型滤油机作为工业废油、废水处理的关键设备,市场需求持续增长。据《2024年中国工业过滤设备市场分析报告》显示,全球…

2025年比较好的mvr蒸发器厂家最新实力排行

2025年比较好的MVR蒸发器厂家最新实力排行行业背景与市场趋势随着全球环保法规日益严格和工业废水处理需求的持续增长,MVR(机械蒸汽再压缩)蒸发器市场迎来了快速发展期。据《2024-2029年中国MVR蒸发器行业市场调研与…

深入解析:PHP 后台通过权限精制飞书多维表格

深入解析:PHP 后台通过权限精制飞书多维表格2025-11-19 08:06 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: b…