博客
关于我
JUnit5学习之七:参数化测试(Parameterized Tests)进阶
阅读量:413 次
发布时间:2019-03-06

本文共 4035 字,大约阅读时间需要 13 分钟。

《JUnit5学习》系列 | 参数化测试高级功能实践

作为《JUnit5学习》系列的第七篇,本篇将在前文《JUnit5学习》系列第六篇《JUnit5参数化测试实战》基础上,深入探讨JUnit5参数化测试的高级功能,包括自定义数据源、参数转换、字段聚合以及测试执行名称自定义等内容。


自定义数据源

在JUnit5的参数化测试中,除了内置的多种数据源(如@CsvSource、@ValueSource等),开发者有时会对数据源的灵活性和定制性有更高的要求。为了实现更深层次的定制,可以通过开发自定义的ArgumentsProvider接口实现类,并使用@ArgumentsSource注解指定数据源。

示例代码:

package com.bolingcavalry.parameterized.service.impl;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import java.util.stream.Stream;
public class MyArgumentsProvider implements ArgumentsProvider {
@Override
public Stream
provideArguments(ExtensionContext context) throws Exception {
return Stream.of("apple4", "banana4")
.map(Arguments::of);
}
}

在测试方法中添加@ArgumentsSource(MyArgumentsProvider.class)注解:

@Order(15)
@DisplayName("ArgumentsProvider接口的实现类提供的数据作为入参")
@ParameterizedTest
@ArgumentsSource(MyArgumentsProvider.class)
void argumentsSourceTest(String candidate) {
log.info("argumentsSourceTest [{}]", candidate);
}

参数转换

JUnit5的参数化测试允许数据源与测试方法的入参类型之间进行自动或手动转换。虽然不一定要求两者类型一致,但通过转换器可以实现更灵活的数据类型适配。

示例代码:

@Order(16)
@DisplayName("int型自动转为double型入参")
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void argumentConversionTest(double candidate) {
log.info("argumentConversionTest [{}]", candidate);
}

当使用@ValueSource注解时,int型数据会自动转换为double型传递给测试方法。

更复杂的转换:

@Order(17)
@DisplayName("string型,指定转换器,转为LocalDate型入参")
@ParameterizedTest
@ValueSource(strings = { "01.01.2017", "31.12.2017" })
void argumentConversionWithConverterTest(
@JavaTimeConversionPattern("dd.MM.yyyy") LocalDate candidate) {
log.info("argumentConversionWithConverterTest [{}]", candidate);
}

通过@JavaTimeConversionPattern注解,可以将字符串日期格式转换为LocalDate类型。


字段聚合(Argument Aggregation)

传统的参数化测试方法需要为每个数据源字段定义一个独立的参数,这在数据源字段较多时会导致代码冗余。JUnit5提供了Argument Aggregation功能,允许将多个字段聚合到一个ArgumentsAccessor对象中。

示例代码:

@Order(18)
@DisplayName("CsvSource的多个字段聚合到ArgumentsAccessor实例")
@ParameterizedTest
@CsvSource({
"Jane1, Doe1, BIG",
"John1, Doe1, SMALL"
})
void argumentsAccessorTest(ArgumentsAccessor arguments) {
Person person = new Person();
person.setFirstName(arguments.getString(0));
person.setLastName(arguments.getString(1));
person.setType(arguments.get(2, Types.class));
log.info("argumentsAccessorTest [{}]", person);
}

更优雅的聚合

为了避免在测试方法中直接处理ArgumentsAccessor对象,可以使用JUnit5提供的@AggregateWith注解,指定一个从ArgumentsAccessor到目标类型的转换器。

转换器实现:

package com.bolingcavalry.parameterized.service.impl;
import org.junit.jupiter.params.aggregator.ArgumentsAccessor;
import org.junit.jupiter.params.aggregator.ArgumentsAggregationException;
import org.junit.jupiter.params.aggregator.ArgumentsAggregator;
public class PersonAggregator implements ArgumentsAggregator {
@Override
public Object aggregateArguments(ArgumentsAccessor arguments, ParameterContext context)
throws ArgumentsAggregationException {
Person person = new Person();
person.setFirstName(arguments.getString(0));
person.setLastName(arguments.getString(1));
person.setType(arguments.get(2, Types.class));
return person;
}
}

测试方法:

@Order(19)
@DisplayName("CsvSource的多个字段,通过指定聚合类转为Person实例")
@ParameterizedTest
@CsvSource({
"Jane2, Doe2, SMALL",
"John2, Doe2, UNKNOWN"
})
void customAggregatorTest(
@AggregateWith(PersonAggregator.class) Person person) {
log.info("customAggregatorTest [{}]", person);
}

测试执行名称自定义

通过@ParameterizedTest注解的name属性,可以为每次测试执行定义一个友好的名称格式。例如:

@Order(20)
@DisplayName("CSV格式多条记录入参(自定义展示名称)")
@ParameterizedTest(name = "序号 [{index}],fruit参数 [{0}],rank参数 [{1}]")
@CsvSource({
"apple3, 31",
"banana3, 32",
"'lemon3, lime3', 0x3A"
})
void csvSourceWithCustomDisplayNameTest(
String fruit, int rank) {
log.info("csvSourceWithCustomDisplayNameTest, fruit [{}], rank [{}]", fruit, rank);
}

总结

通过本文的实践,熟悉了JUnit5参数化测试的高级功能,包括自定义数据源、参数转换、字段聚合以及测试执行名称自定义等。在实际项目中,合理使用这些功能可以显著提升单元测试的代码质量和效率。

转载地址:http://uhtkz.baihongyu.com/

你可能感兴趣的文章
Nokia5233手机和我装的几个symbian V5手机软件
查看>>
Non-final field ‘code‘ in enum StateEnum‘
查看>>
none 和 host 网络的适用场景 - 每天5分钟玩转 Docker 容器技术(31)
查看>>
None还可以是函数定义可选参数的一个默认值,设置成默认值时实参在调用该函数时可以不输入与None绑定的元素...
查看>>
NoNodeAvailableException None of the configured nodes are available异常
查看>>
Vue.js 学习总结(16)—— 为什么 :deep、/deep/、>>> 样式能穿透到子组件
查看>>
NOPI读取Excel
查看>>
NoSQL&MongoDB
查看>>
NoSQL介绍
查看>>
NoSQL数据库概述
查看>>
Notadd —— 基于 nest.js 的微服务开发框架
查看>>
Notepad ++ 安装与配置教程(非常详细)从零基础入门到精通,看完这一篇就够了
查看>>
Notepad++在线和离线安装JSON格式化插件
查看>>
notepad++最详情汇总
查看>>
notepad如何自动对齐_notepad++怎么自动排版
查看>>
Notes on Paul Irish's "Things I learned from the jQuery source" casts
查看>>
Notification 使用详解(很全
查看>>
NotImplementedError: Cannot copy out of meta tensor; no data! Please use torch.nn.Module.to_empty()
查看>>
Now trying to drop the old temporary tablespace, the session hangs.
查看>>
nowcoder—Beauty of Trees
查看>>