JUnit参数化测试

时间:2020-02-23 14:35:24  来源:igfitidea点击:

JUnit参数化测试允许我们使用不同的参数多次运行测试方法。
JUnit 5提供了许多将参数传递给测试方法的方法。

JUnit参数化测试

我们需要遵循其他依赖关系才能在测试案例中使用参数化测试。

<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-params</artifactId>
	<version>5.2.0</version>
	<scope>test</scope>
</dependency>

我们必须使用带有测试方法的@ParameterizedTest来代替通用的@Test注解。

我们还必须提供一个将为该方法生成参数的源。
我们可以在参数化测试方法中定义和使用多种类型的源。

使用@ValueSource的JUnit参数化测试

这是参数化测试的最简单形式,我们可以使用@ValueSource传递参数数组。
我们可以使用ValueSource批注传递原始数据类型数组,字符串数组或者类数组。

@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void test_ValueSource(int i) {
	System.out.println(i);
}

@ParameterizedTest
@ValueSource(strings = { "1", "2", "3" })
void test_ValueSource_String(String s) {
	assertTrue(Integer.parseInt(s) < 5);
}

JUnit @ParameterizedTest与@EnumSource

@EnumSource允许我们将枚举传递给我们的测试方法。

@ParameterizedTest
@EnumSource(ElementType.class)
void test_EnumSource(ElementType et) {
	System.out.println(et);
}

如果只需要Enum中的特定值,则可以使用EnumSource name参数来实现。

@ParameterizedTest
@EnumSource(value = ElementType.class, names = { "TYPE", "METHOD", "FIELD" })
void test_EnumSource_Extended(ElementType et) {
	assertTrue(EnumSet.of(ElementType.FIELD, ElementType.TYPE, ElementType.METHOD).contains(et));
}

使用@MethodSource的JUnit @ParameterizedTest

我们可以使用@MethodSource来指定测试参数的工厂方法。
此方法可以存在于同一类或者任何其他类中。
工厂方法应该是静态的,并返回Strem,Iterator,Iterable或者元素数组。

@ParameterizedTest
@MethodSource("ms")
void test_MethodSource(String s) {
	assertNotNull(s);
}

static Stream<String> ms() {
	return Stream.of("A", "B");
}

我们还可以使用MethodSource将多个参数传递给测试方法。
在这种情况下,我们将不得不使用ArgumentsAPI。
让我们用工厂方法源定义一个单独的类。

package com.theitroad.parameterizedtests;

import java.util.stream.Stream;

import org.junit.jupiter.params.provider.Arguments;

public class MethodSources {

	public static Stream<Arguments> msMP() {
		return Stream.of(Arguments.of(1, "A"), Arguments.of(2, "B"), Arguments.of(3, "C"));
	}
}

相应的JUnit参数化测试方法将定义为:

@ParameterizedTest
@MethodSource("com.theitroad.parameterizedtests.MethodSources#msMP")
void test_MethodSource_MultipleParams(int i, String s) {
	assertTrue(4 > i);
	assertTrue(Arrays.asList("A", "B", "C").contains(s));
}

JUnit MethodSource与TestNG DataProvider批注非常相似。

JUnit @ParameterizedTest与@CsvSource

我们还可以将CSV值传递给测试方法。
我们可以在测试方法中为多个参数指定分隔符。

@ParameterizedTest
@CsvSource(delimiter='|', value= {"1|'A'","2|B"})
void test_CsvSource(int i, String s) {
	assertTrue(3 > i);
	assertTrue(Arrays.asList("A", "B", "C").contains(s));
}

带有CSV文件的JUnit参数化测试

我们可以使用@CsvFileSource批注将CSV数据从文件传递到参数化测试方法。
我们可以跳过标题行并定义我们的自定义定界符。

假设我们将" country_code.csv"文件定义为:

Country,TelephoneCode
USA,1
San Franceco,91

这是将CSV文件数据用于参数映射的测试方法。

@ParameterizedTest
@CsvFileSource(resources = "/country_code.csv", numLinesToSkip = 1)
void test_CsvFileSource(String country, int code) {
  assertNotNull(country);
  assertTrue(0 < code);
}

带对象的JUnit参数化测试

到目前为止,我们在示例中使用了基元和字符串,但是在现实生活中,大多数时候我们都必须传递对象。
我们可以使用@MethodSource来实现此功能。

假设我们将Book类定义为:

class Book {
	private String title;
	//standard getter setters

	public Book(String t) {
		this.title = t;
	}
	
	@Override
	public String toString() {
		return title;
	}
}

现在,我们可以使用以下工厂方法将Book对象传递给我们的测试方法。

static Book[] mpBooks() {
	return new Book[] {new Book("Harry Potter"), new Book("Five Point Someone")};
}

@ParameterizedTest
@MethodSource("mpBooks")
void test_MethodSource_Objects(Book b) {
	assertNotNull(b.getTitle());
}

请注意,这一次我返回的是Book数组,而之前我返回的是元素流。

JUnit参数化测试参数验证

如果要通过Eclipse运行测试用例,则可以检查方法参数以确保将正确的值传递给参数化测试。

JUnit测试方法参数转换

JUnit为许多类型转换器提供内置支持。
其中一些是int到long,字符串是boolean,反之亦然,字符串是enum,是日期时间对象。
下面的代码也将起作用,并且JUnit将自动调用我们的Book类构造函数以将String值转换为Book对象。

@ParameterizedTest
@ValueSource(strings = {"Harry Potter", "Hamlet"})
void test_ValueSource_Objects(Book b) {
	assertNotNull(b.getTitle());
}

但是,如果更改Book类的构造函数,则在执行测试用例时可能会导致错误。
最好使用MethodSource并提供我们自己的对象创建机制。