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

本文共 3958 字,大约阅读时间需要 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/

你可能感兴趣的文章
Netty核心模块组件
查看>>
Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
查看>>
Netty源码—2.Reactor线程模型一
查看>>
Netty源码—4.客户端接入流程一
查看>>
Netty源码—4.客户端接入流程二
查看>>
Netty源码—5.Pipeline和Handler一
查看>>
Netty源码—6.ByteBuf原理二
查看>>
Netty源码—7.ByteBuf原理三
查看>>
Netty源码—7.ByteBuf原理四
查看>>
Netty源码—8.编解码原理二
查看>>
Netty源码解读
查看>>
Netty的Socket编程详解-搭建服务端与客户端并进行数据传输
查看>>
Netty相关
查看>>
Network Dissection:Quantifying Interpretability of Deep Visual Representations(深层视觉表征的量化解释)
查看>>
Network Sniffer and Connection Analyzer
查看>>
NetworkX系列教程(11)-graph和其他数据格式转换
查看>>
Networkx读取军械调查-ITN综合传输网络?/读取GML文件
查看>>
Net与Flex入门
查看>>
net包之IPConn
查看>>
NFinal学习笔记 02—NFinalBuild
查看>>