在 JUnit 5 中参数化 class 和测试
Parameterize both class and tests in JUnit 5
有没有一种方法可以同时参数化测试 class(就像您可以在 JUnit 4 中使用 Parameterized
和 @Parameters
一样)和测试方法(就像您可以在 JUnitParams 中使用JUnit 4 或 JUnit 5 中的 @ParameterizedTest
)?最后需要得到参数的笛卡尔积
java.nio.ByteBuffer
使用所需方法的部分测试示例:
public class ByteBufferTest {
private static final int BUFFER_SIZE = 16384;
private final ByteOrder byteOrder;
private ByteBuffer sut;
@Factory(dataProvider = "byteOrders")
public ByteBufferTest(ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
@DataProvider
public static Object[][] byteOrders() {
return new Object[][] {
{ByteOrder.BIG_ENDIAN},
{ByteOrder.LITTLE_ENDIAN}
};
}
@BeforeMethod
public void setUp() {
sut = ByteBuffer.allocate(BUFFER_SIZE);
sut.order(byteOrder);
}
@Test(dataProvider = "validPositions")
public void position(int position) {
System.out.println(byteOrder + " position " + position);
sut.position(position);
assertThat(sut.position()).isEqualTo(position);
}
@DataProvider
public static Object[][] validPositions() {
return new Object[][] {{0}, {1}, {BUFFER_SIZE - 1}};
}
@Test(dataProvider = "intPositionsAndValues")
public void putInt(int position, int value, byte[] expected) {
System.out.println(byteOrder + " position " + position + " value " + value);
sut.putInt(position, value);
assertThat(sut.array())
.contains(expected[0], atIndex(position))
.contains(expected[1], atIndex(position + 1))
.contains(expected[2], atIndex(position + 2))
.contains(expected[3], atIndex(position + 3));
}
@DataProvider
public Object[][] intPositionsAndValues() {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return new Object[][]{
{0, 0, new byte[4]},
{5, 123456789, new byte[] {0x07, 0x5B, (byte) 0xCD, 0x15}},
};
} else {
return new Object[][]{
{0, 0, new byte[4]},
{5, 123456789, new byte[] {0x15, (byte) 0xCD, 0x5B, 0x07}},
};
}
}
}
它产生:
LITTLE_ENDIAN position 0
LITTLE_ENDIAN position 1
LITTLE_ENDIAN position 16383
BIG_ENDIAN position 0
BIG_ENDIAN position 1
BIG_ENDIAN position 16383
LITTLE_ENDIAN position 0 value 0
LITTLE_ENDIAN position 5 value 123456789
BIG_ENDIAN position 0 value 0
BIG_ENDIAN position 5 value 123456789
我们正在考虑从 TestNG 迁移到 JUnit 5,但我们经常使用这种东西。在上面的示例中使用字节顺序作为 class 级参数并非巧合:我们经常需要测试各种二进制数据处理器,其中测试构造函数将采用 byte/bit 顺序参数,我们 运行 对 Big Endian 和 Little Endian 的每个测试。
我正在考虑为此创建一个扩展然后使用 ExtendWith
,但也许有一个现有的扩展或我错过的开箱即用的东西?
JUnit 木星(香草)
您可以组合多个来源,例如一个@MethodSource
。基于您的 TestNG 示例:
class ExampleTest {
@ParameterizedTest
@MethodSource("args")
void test(String classParameter, String testParameter) {
System.out.println(classParameter + " " + testParameter);
}
static Stream<Arguments> args() {
return classParameters().flatMap(
classParameter -> testParameters().map(
testParameter -> Arguments.of(classParameter, testParameter)));
}
static Stream<String> classParameters() {
return Stream.of("classParam1", "classParam2");
}
static Stream<String> testParameters() {
return Stream.of("testParam1", "testParam2");
}
}
这会产生:
classParam1 testParam1
classParam1 testParam2
classParam2 testParam1
classParam2 testParam2
应 的要求,这里是“一个至少包含两个具有不同参数集的测试方法的示例”:
class ExampleTest {
static Stream<String> classParams() {
return Stream.of("classParam1", "classParam2", "classParam3");
}
static Stream<Arguments> withClassParams(List<?> methodParams) {
return classParams().flatMap(
classParam -> methodParams.stream().map(
methodParam -> Arguments.of(classParam, methodParam)));
}
@ParameterizedTest
@MethodSource
void booleanParams(String classParam, boolean booleanParam) {
System.out.println(classParam + " " + booleanParam);
}
static Stream<Arguments> booleanParams() {
return withClassParams(List.of(false, true));
}
@ParameterizedTest
@MethodSource
void integerParams(String classParam, int integerParam) {
System.out.println(classParam + " " + integerParam);
}
static Stream<Arguments> integerParams() {
return withClassParams(List.of(1, 2, 3, 4, 5, 6));
}
@ParameterizedTest
@MethodSource
void objectParams(String classParam, Object objectParam) {
System.out.println(classParam + " " + objectParam);
}
static Stream<Arguments> objectParams() {
return withClassParams(List.of(new Object()));
}
}
3 class 个参数加上 3 个不同类型和大小的方法参数,产生以下输出:
classParam1 java.lang.Object@35cabb2a
classParam2 java.lang.Object@35cabb2a
classParam3 java.lang.Object@35cabb2a
classParam1 1
classParam1 2
classParam1 3
classParam1 4
classParam1 5
classParam1 6
classParam2 1
classParam2 2
classParam2 3
classParam2 4
classParam2 5
classParam2 6
classParam3 1
classParam3 2
classParam3 3
classParam3 4
classParam3 5
classParam3 6
classParam1 false
classParam1 true
classParam2 false
classParam2 true
classParam3 false
classParam3 true
JUnit 先锋
JUnit Jupiter 有 JUnit Pioneer 扩展包。它带有 @CartesianProductTest
。使用上面的扩展示例:
class CartProdTest {
@CartesianProductTest(factory = "classWithObjectParams")
void testClassWithObject(String classParam, Object objectParam) {
System.out.println(classParam + " " + objectParam);
}
static CartesianProductTest.Sets classWithObjectParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(new Object());
}
@CartesianProductTest(factory = "classWithIntegerParams")
void testClassWithInteger(String classParam, int integerParam) {
System.out.println(classParam + " " + integerParam);
}
static CartesianProductTest.Sets classWithIntegerParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(1, 2, 3, 4, 5, 6);
}
@CartesianProductTest(factory = "classWithBooleanParams")
void testClassWithBoolean(String classParam, boolean booleanParam) {
System.out.println(classParam + " " + booleanParam);
}
static CartesianProductTest.Sets classWithBooleanParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(false, true);
}
static Stream<String> classParams() {
return Stream.of("classParam1", "classParam2", "classParam3");
}
}
这会产生相同的输出。
有没有一种方法可以同时参数化测试 class(就像您可以在 JUnit 4 中使用 Parameterized
和 @Parameters
一样)和测试方法(就像您可以在 JUnitParams 中使用JUnit 4 或 JUnit 5 中的 @ParameterizedTest
)?最后需要得到参数的笛卡尔积
java.nio.ByteBuffer
使用所需方法的部分测试示例:
public class ByteBufferTest {
private static final int BUFFER_SIZE = 16384;
private final ByteOrder byteOrder;
private ByteBuffer sut;
@Factory(dataProvider = "byteOrders")
public ByteBufferTest(ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
@DataProvider
public static Object[][] byteOrders() {
return new Object[][] {
{ByteOrder.BIG_ENDIAN},
{ByteOrder.LITTLE_ENDIAN}
};
}
@BeforeMethod
public void setUp() {
sut = ByteBuffer.allocate(BUFFER_SIZE);
sut.order(byteOrder);
}
@Test(dataProvider = "validPositions")
public void position(int position) {
System.out.println(byteOrder + " position " + position);
sut.position(position);
assertThat(sut.position()).isEqualTo(position);
}
@DataProvider
public static Object[][] validPositions() {
return new Object[][] {{0}, {1}, {BUFFER_SIZE - 1}};
}
@Test(dataProvider = "intPositionsAndValues")
public void putInt(int position, int value, byte[] expected) {
System.out.println(byteOrder + " position " + position + " value " + value);
sut.putInt(position, value);
assertThat(sut.array())
.contains(expected[0], atIndex(position))
.contains(expected[1], atIndex(position + 1))
.contains(expected[2], atIndex(position + 2))
.contains(expected[3], atIndex(position + 3));
}
@DataProvider
public Object[][] intPositionsAndValues() {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return new Object[][]{
{0, 0, new byte[4]},
{5, 123456789, new byte[] {0x07, 0x5B, (byte) 0xCD, 0x15}},
};
} else {
return new Object[][]{
{0, 0, new byte[4]},
{5, 123456789, new byte[] {0x15, (byte) 0xCD, 0x5B, 0x07}},
};
}
}
}
它产生:
LITTLE_ENDIAN position 0
LITTLE_ENDIAN position 1
LITTLE_ENDIAN position 16383
BIG_ENDIAN position 0
BIG_ENDIAN position 1
BIG_ENDIAN position 16383
LITTLE_ENDIAN position 0 value 0
LITTLE_ENDIAN position 5 value 123456789
BIG_ENDIAN position 0 value 0
BIG_ENDIAN position 5 value 123456789
我们正在考虑从 TestNG 迁移到 JUnit 5,但我们经常使用这种东西。在上面的示例中使用字节顺序作为 class 级参数并非巧合:我们经常需要测试各种二进制数据处理器,其中测试构造函数将采用 byte/bit 顺序参数,我们 运行 对 Big Endian 和 Little Endian 的每个测试。
我正在考虑为此创建一个扩展然后使用 ExtendWith
,但也许有一个现有的扩展或我错过的开箱即用的东西?
JUnit 木星(香草)
您可以组合多个来源,例如一个@MethodSource
。基于您的 TestNG 示例:
class ExampleTest {
@ParameterizedTest
@MethodSource("args")
void test(String classParameter, String testParameter) {
System.out.println(classParameter + " " + testParameter);
}
static Stream<Arguments> args() {
return classParameters().flatMap(
classParameter -> testParameters().map(
testParameter -> Arguments.of(classParameter, testParameter)));
}
static Stream<String> classParameters() {
return Stream.of("classParam1", "classParam2");
}
static Stream<String> testParameters() {
return Stream.of("testParam1", "testParam2");
}
}
这会产生:
classParam1 testParam1
classParam1 testParam2
classParam2 testParam1
classParam2 testParam2
应
class ExampleTest {
static Stream<String> classParams() {
return Stream.of("classParam1", "classParam2", "classParam3");
}
static Stream<Arguments> withClassParams(List<?> methodParams) {
return classParams().flatMap(
classParam -> methodParams.stream().map(
methodParam -> Arguments.of(classParam, methodParam)));
}
@ParameterizedTest
@MethodSource
void booleanParams(String classParam, boolean booleanParam) {
System.out.println(classParam + " " + booleanParam);
}
static Stream<Arguments> booleanParams() {
return withClassParams(List.of(false, true));
}
@ParameterizedTest
@MethodSource
void integerParams(String classParam, int integerParam) {
System.out.println(classParam + " " + integerParam);
}
static Stream<Arguments> integerParams() {
return withClassParams(List.of(1, 2, 3, 4, 5, 6));
}
@ParameterizedTest
@MethodSource
void objectParams(String classParam, Object objectParam) {
System.out.println(classParam + " " + objectParam);
}
static Stream<Arguments> objectParams() {
return withClassParams(List.of(new Object()));
}
}
3 class 个参数加上 3 个不同类型和大小的方法参数,产生以下输出:
classParam1 java.lang.Object@35cabb2a
classParam2 java.lang.Object@35cabb2a
classParam3 java.lang.Object@35cabb2a
classParam1 1
classParam1 2
classParam1 3
classParam1 4
classParam1 5
classParam1 6
classParam2 1
classParam2 2
classParam2 3
classParam2 4
classParam2 5
classParam2 6
classParam3 1
classParam3 2
classParam3 3
classParam3 4
classParam3 5
classParam3 6
classParam1 false
classParam1 true
classParam2 false
classParam2 true
classParam3 false
classParam3 true
JUnit 先锋
JUnit Jupiter 有 JUnit Pioneer 扩展包。它带有 @CartesianProductTest
。使用上面的扩展示例:
class CartProdTest {
@CartesianProductTest(factory = "classWithObjectParams")
void testClassWithObject(String classParam, Object objectParam) {
System.out.println(classParam + " " + objectParam);
}
static CartesianProductTest.Sets classWithObjectParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(new Object());
}
@CartesianProductTest(factory = "classWithIntegerParams")
void testClassWithInteger(String classParam, int integerParam) {
System.out.println(classParam + " " + integerParam);
}
static CartesianProductTest.Sets classWithIntegerParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(1, 2, 3, 4, 5, 6);
}
@CartesianProductTest(factory = "classWithBooleanParams")
void testClassWithBoolean(String classParam, boolean booleanParam) {
System.out.println(classParam + " " + booleanParam);
}
static CartesianProductTest.Sets classWithBooleanParams() {
return new CartesianProductTest.Sets()
.addAll(classParams())
.add(false, true);
}
static Stream<String> classParams() {
return Stream.of("classParam1", "classParam2", "classParam3");
}
}
这会产生相同的输出。