单元测试 —— JUnit 5 参数化测试_idea单元测试 csvsource null 传递

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注软件测试)
img

正文

JUnit 5参数化测试

目录

  • 设置
  • 我们的第一个参数化测试
  • 参数来源
  • @ValueSource
  • @NullSource & @EmptySource
  • @MethodSource
  • @CsvSource
  • @CsvFileSource
  • @EnumSource
  • @ArgumentsSource
  • 参数转换
  • 参数聚合
  • 奖励

如果您正在阅读这篇文章,说明您已经熟悉了JUnit。让我为您概括一下JUnit——在软件开发中,我们开发人员编写的代码可能是设计一个人的个人资料这样简单,也可能是在银行系统中进行付款这样复杂。在开发这些功能时,我们倾向于编写单元测试。顾名思义,单元测试的主要目的是确保代码的小、单独部分按预期功能工作。

如果单元测试执行失败,这意味着该功能无法按预期工作。编写单元测试的一种工具是JUnit。这些单元测试程序很小,但是非常强大,并且可以快速执行。现在我们已经了解了JUnit,接下来让我们聚焦于JUnit 5中的参数化测试。

参数化测试可以解决在为任何新/旧功能开发测试框架时遇到的最常见问题。

  • 编写针对每个可能输入的测试用例变得更加容易。
  • 单个测试用例可以接受多个输入来测试源代码,有助于减少代码重复。
  • 通过使用多个输入运行单个测试用例,我们可以确信已涵盖所有可能的场景,并维护更好的代码覆盖率。

开发团队通过利用方法和类来创建可重用且松散耦合的源代码。传递给代码的参数会影响其功能。例如,计算器类中的sum方法可以处理整数和浮点数值。JUnit 5引入了执行参数化测试的能力,可以使用单个测试用例测试源代码,该测试用例可以接受不同的输入。这样可以更有效地进行测试,因为在旧版本的JUnit中,必须为每种输入类型创建单独的测试用例,从而导致大量的代码重复。

示例代码

本文附带有在 GitHub上(
code-examples/core-java/junit5-parameterized-tests at master · thombergs/code-examples · GitHub) 的一个可工作的示例代码。

设置

就像疯狂泰坦灭霸喜欢访问力量一样,您可以使用以下Maven依赖项来访问JUnit5中参数化测试的力量:

org.junit.jupiter junit-jupiter-params 5.9.2 test

让我们来写些代码,好吗?

我们的第一个参数化测试

现在,我想向您介绍一个新的注解 @ParameterizedTest。顾名思义,它告诉JUnit引擎使用不同的输入值运行此测试。

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class ValueSourceTest {

@ParameterizedTest
@ValueSource(ints = { 2, 4 })
void checkEvenNumber(int number) {
assertEquals(0, number % 2,
“Supplied number is not an even number”);
}
}

在上面的示例中,注解@ValueSource为 checkEvenNumber() 方法提供了多个输入。假设我们使用JUnit4编写相同的代码,即使它们的结果(断言)完全相同,我们也必须编写2个测试用例来覆盖输入2和4。

当我们执行 ValueSourceTest 时,我们会看到什么:

ValueSourceTest

|_ checkEvenNumber

|_ [1] 2

|_ [2] 4

这意味着 checkEvenNumber() 方法将使用2个输入值执行。

在下一节中,让我们学习一下JUnit5框架提供的各种参数来源。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:110685036

参数来源

JUnit5提供了许多参数来源注释。下面的章节将简要概述其中一些注释并提供示例。

@ValueSource

@ValueSource是一个简单的参数源,可以接受单个字面值数组。@ValueSource支持的字面值类型有short、byte、int、long、float、double、char、boolean、String和Class。

@ParameterizedTest
@ValueSource(strings = { “a1”, “b2” })
void checkAlphanumeric(String word) {
assertTrue(StringUtils.isAlphanumeric(word),
“Supplied word is not alpha-numeric”);
}

@NullSource & @EmptySource

假设我们需要验证用户是否已经提供了所有必填字段(例如在登录函数中需要提供用户名和密码)。我们使用注解来检查提供的字段是否为 null,空字符串或空格。

  • 在单元测试中使用 @NullSource 和 @EmptySource 可以帮助我们提供带有 null、空字符串和空格的数据源,并验证源代码的行为。

@ParameterizedTest
@NullSource
void checkNull(String value) {
assertEquals(null, value);
}

@ParameterizedTest
@EmptySource
void checkEmpty(String value) {
assertEquals(“”, value);
}

  • 我们还可以使用 @NullAndEmptySource 注解来组合传递 null 和空输入。

@ParameterizedTest
@NullAndEmptySource
void checkNullAndEmpty(String value) {
assertTrue(value == null || value.isEmpty());
}

  • 另一个传递 null、空字符串和空格输入值的技巧是结合使用 @NullAndEmptySource 注解,以覆盖所有可能的负面情况。该注解允许我们从一个或多个测试类的工厂方法中加载输入,并生成一个参数流。

@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = { " ", " " })
void checkNullEmptyAndBlank(String value) {
assertTrue(value == null || value.isBlank());
}

@MethodSource

该注解允许我们从一个或多个测试类的工厂方法中加载输入,并生成一个参数流。

  • 显式方法源 - 测试将尝试加载提供的方法。

// Note: The test will try to load the supplied method
@ParameterizedTest
@MethodSource(“checkExplicitMethodSourceArgs”)
void checkExplicitMethodSource(String word) {
assertTrue(StringUtils.isAlphanumeric(word),
“Supplied word is not alpha-numeric”);
}

static Stream checkExplicitMethodSourceArgs() {
return Stream.of(“a1”,
“b2”);
}

  • 隐式方法源 - 测试将搜索与测试类匹配的源方法。

// Note: The test will search for the source method
// that matches the test-case method name
@ParameterizedTest
@MethodSource
void checkImplicitMethodSource(String word) {
assertTrue(StringUtils.isAlphanumeric(word),
“Supplied word is not alpha-numeric”);
}

static Stream checkImplicitMethodSource() {
return Stream.of(“a1”,
“b2”);
}

  • 多参数方法源 - 我们必须将输入作为参数流传递。测试将按照索引顺序加载参数。

// Note: The test will automatically map arguments based on the index
@ParameterizedTest
@MethodSource
void checkMultiArgumentsMethodSource(int number, String expected) {
assertEquals(StringUtils.equals(expected, “even”) ? 0 : 1, number % 2);
}

static Stream checkMultiArgumentsMethodSource() {
return Stream.of(Arguments.of(2, “even”),
Arguments.of(3, “odd”));
}

  • 外部方法源 - 测试将尝试加载外部方法。

// Note: The test will try to load the external method
@ParameterizedTest
@MethodSource(
“source.method.ExternalMethodSource#checkExternalMethodSourceArgs”)
void checkExternalMethodSource(String word) {
assertTrue(StringUtils.isAlphanumeric(word),
“Supplied word is not alpha-numeric”);
}
// Note: The test will try to load the external method@ParameterizedTest@MethodSource(“source.method.ExternalMethodSource#checkExternalMethodSourceArgs”)void checkExternalMethodSource(String word) { assertTrue(StringUtils.isAlphanumeric(word),“Supplied word is not alpha-numeric”);}

package source.method;
import java.util.stream.Stream;

public class ExternalMethodSource {
static Stream checkExternalMethodSourceArgs() {
return Stream.of(“a1”,
“b2”);
}
}

@CsvSource

该注解允许我们将参数列表作为逗号分隔的值(即 CSV 字符串字面量)传递,每个 CSV 记录都会导致执行一次参数化测试。它还支持使用 useHeadersInDisplayName属性跳过 CSV 标头。

@ParameterizedTest
@CsvSource({ “2, even”,
“3, odd”})
void checkCsvSource(int number, String expected) {
assertEquals(StringUtils.equals(expected, “even”)
? 0 : 1, number % 2);
}

@CsvFileSource

该注解允许我们使用类路径或本地文件系统中的逗号分隔值(CSV)文件。与 @CsvSource 类似,每个 CSV 记录都会导致执行一次参数化测试。它还支持各种其他属性 -numLinesToSkip、useHeadersInDisplayName、lineSeparator、delimiterString等。

示例 1: 基本实现

@ParameterizedTest
@CsvFileSource(
files = “src/test/resources/csv-file-source.csv”,
numLinesToSkip = 1)
void checkCsvFileSource(int number, String expected) {
assertEquals(StringUtils.equals(expected, “even”)
? 0 : 1, number % 2);
}

src/test/resources/csv-file-source.csv

NUMBER, ODD_EVEN

2, even

3, odd

示例2:使用属性

@ParameterizedTest
@CsvFileSource(
files = “src/test/resources/csv-file-source_attributes.csv”,
delimiterString = “|”,
lineSeparator = “||”,
numLinesToSkip = 1)
void checkCsvFileSourceAttributes(int number, String expected) {
assertEquals(StringUtils.equals(expected, “even”)
? 0 : 1, number % 2);
}

src/test/resources/csv-file-source_attributes.csv

|| NUMBER | ODD_EVEN ||

|| 2 | even ||

|| 3 | odd ||

@EnumSource

该注解提供了一种方便的方法来使用枚举常量作为测试用例参数。支持的属性包括:

  • value - 枚举类类型,例如 ChronoUnit.class

package java.time.temporal;

public enum ChronoUnit implements TemporalUnit {
SECONDS(“Seconds”, Duration.ofSeconds(1)),
MINUTES(“Minutes”, Duration.ofSeconds(60)),
HOURS(“Hours”, Duration.ofSeconds(3600)),
DAYS(“Days”, Duration.ofSeconds(86400)),
//12 other units
}

ChronoUnit 是一个包含标准日期周期单位的枚举类型。

@ParameterizedTest
@EnumSource(ChronoUnit.class)
void checkEnumSourceValue(ChronoUnit unit) {
assertNotNull(unit);
}

在此示例中,@EnumSource 将传递所有16个 ChronoUnit 枚举值作为参数。

  • names - 枚举常量的名称或选择名称的正则表达式,例如 DAYS 或 ^.*DAYS$

@ParameterizedTest
@EnumSource(names = { “DAYS”, “HOURS” })
void checkEnumSourceNames(ChronoUnit unit) {
assertNotNull(unit);
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • names - 枚举常量的名称或选择名称的正则表达式,例如 DAYS 或 ^.*DAYS$

@ParameterizedTest
@EnumSource(names = { “DAYS”, “HOURS” })
void checkEnumSourceNames(ChronoUnit unit) {
assertNotNull(unit);
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-XhQhnKxi-1713471480528)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值