前几天在介绍mockito
时候, 提到过一点junit5
里的参数化测试:
今天详细来介绍下这东西的用法.
简介
参数化测试, 俗称Parameterized Tests
, 相对于普通测试, 参数化测试的主要特点在于输入和输出数据
的参数化
.
普通的测试代码写起来像是这样的:
试试看 1 + 1 == 2
试试看 1 + 2 == 3
有了参数化测试, 代码写起来就更像是这样的:
试试 a + b == c, 变量从****取
文化水平,就从刚学过算术的小学生, 突然上升到学了代数的初中生了.
最简单的作品
最简单的参数化测试, 这么写就可以.
@ParameterizedTest
void lessThanTen(int n) {
assertTrue(n < 10);
}
这里添加了一个@ParameterizedTest
注解, 这个测试就是参数化测试了, 接收一个参数int
.
最简单的参数来源
当然, 前面的测试不能跑, 因为他没有数据来源(source)
. 最简单的指定方式, 就是@ValueSource
, 直接传入一份数据.
@ValueSource(ints = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 })
@ParameterizedTest
void lessThanTen(int n) {
assertTrue(n < 10);
}
这个测试基本就算是成型了, 用了最简单的参数源.
方法参数源
我们也可以用动态性更强的参数源, 比如上次用过的函数作为来源@MethodSource
.
@ParameterizedTest
@MethodSource(value = "addSource")
void add(int a, int b, int expected) {
assertEquals(a + b, expected);
}
static Stream<Arguments> addSource() {
return IntStream.rangeClosed(1, 100)
.boxed()
.map(n -> Arguments.of(n, n, 2 * n));
}
这次没有用同名函数,而是传了函数名. 关键就在于加上一个静态函数
返回可迭代的内容或者Stream作为数据源.
高级数据源
除了前面的两个, 还有很多其他的source
可以使用,不过我更喜欢的是 用@JSONSource
.
用法如下:
准备数据文件,jsondata.json
.
[
"1",
"2",
"3",
"4"
]
准备测试, 然后指向参数json文件
@ParameterizedTest
@JSONSource("jsondata.json")
void json(String s) {
log.info(s);
assertNotNull(s);
}
如果参数复杂化,也可以,通过注解指定参数类型,例子如下.
@ParameterizedTest
@JSONSource(value = "pojo.json", type = A.class)
void pojo(A a) {
log.info("data {}", a);
assertNotNull(a);
assertEquals(a.a+a.b, a.c);
}
这时候的数据文件如下:
[
{
"a": 1,
"b": 2,
"c": 3
},
{
"a": 1,
"b": 5,
"c": 6
},
{
"a": 7,
"b": 2,
"c": 5
},
{
"a": 4,
"b": 2,
"c": 6
}
]
这时候参数化测试的能力一样是可以用的. 而且这里最大的好处是,在升级JDK用上 text block
之前, 写json入参可以容易一点点.JSON拼接多行JSON简直是噩梦。
注解内容
当然前面的注解在Junit里找不到, 因为这玩意是我自己写的.
junit这里提供了强大的自定义能力,我们只需要添加1个注解一个注解处理类就行.(如果不想自定义注解, 直接使用处理类也可以).
刚刚用的2个类如下:
import org.junit.jupiter.params.provider.ArgumentsSource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
//关键在这句, 指定provider是谁。 单独用到方法上也行。
@ArgumentsSource(JSONArgumentsProvider.class)
public @interface JSONSource {
String value();
Class type() default String.class;
}
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.support.AnnotationConsumer;//偷懒用了spring的classpath加载。
import org.springframework.core.io.ClassPathResource;
import java.io.File;
import java.util.List;
import java.util.stream.Stream;
//后一个接口是为了传参数, 消化掉注解传入的类型。
public class JSONArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<JSONSource> {
String jsonFileName;
Class type;
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
ClassPathResource resource = new ClassPathResource(jsonFileName);
File file = resource.getFile();
List<?> list = new ObjectMapper().readerForListOf(type).readValue(file);
return list.stream().map(Arguments::of);
}
@Override
public void accept(JSONSource jsonSource) {
jsonFileName = jsonSource.value();
type = jsonSource.type();
}
}
后话
好了, 今天关于Junit5 参数化测试的介绍就到这里,详情最好还是看文档,https://junit.org/junit5 。 我这里只是极端简化了一下。希望对你有用。
原文始发于微信公众号(K字的研究):1.5分钟学会用Junit参数化测试
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/41696.html