章
目
录
在我之前关于这个主题的帖子中,我介绍了如何使用@Parameters注释编写参数化测试用例。 如果我用正确的词,那么这种方法可能很混乱,而且不太容易阅读。 这需要很多不必要的注意力。 好吧,还有另一种方法可以帮助您使用JUnit中的注释,如@Theory 和@DataPoints来编写参数化测试用例。
我将以前面的例子为例,并将其转换为新的方法。 这只是为了说明,因为在这之后我们将能够比较什么被改变了,以及与以前的做法有多大的不同。
1)使用@DataPoints提供输入数据
在这里,只有注释已经从@Parameters更改为@DataPoints。 其余的概念是相同的。
以前,提供输入的方法是:
@Parameters(name = "Run #Square of : {0}^2={1}")
public static Iterable<Object []> data() {
return Arrays.asList(new Object[][] { { 1, 1 }, { 2, 4 }, { 3, 19 },
{ 4, 16 }, { 5, 25 } });
}
现在,它是:
@DataPoints
public static int[][] integers()
{
return new int[][]{{1, 1}, {2, 4}, {3, 9}, {4, 16}, {5, 25}, {}};
}
请注意,您可以使用@DataPoint注释单独编写输入。
@DataPoint
public static int[] input6 = new int[]{6, 36};
@DataPoint
public static int[] input7 = new int[]{7, 49};
我已经将返回类型从“Iterable<object[]>”更改为“int[][]”,因为这些输入被提供给测试用例的方式有所不同。 在下一部分中,您将看到区别。
2)使用@Theory编写测试用例
基于理论的类在结构上比参数化测试类更简单。 类声明应该用@RunWith(Theories.class)注释,并且必须提供两个实体:
- 一个生成和返回测试数据的data方法
- 一个Theory
Data方法必须用@DataPoints注释,每个理论必须用@Theory注释。 与普通的单元测试一样,每个理论应至少包含一个断言。
在先前的做法中,我们这样编写测试用例:
@Test
public void testUserMapping() {
//这里可以使用断言
Assert.assertEquals(resultExpected, MathUtils.square(input));
}
其中input和resultExpected被声明为类成员并使用参数化构造函数填充。 正如您在上面看到的那样,testUserMapping()方法没有任何参数。
在新方法中,测试用例被标注为@Theory注释。例如:
@Theory
public void testSquares(final int[] inputs)
{
Assume.assumeTrue(inputs[0] > 0 && inputs[1] > 0);
Assert.assertEquals(inputs[1], MathUtils.square(inputs[0]));
}
您现在看到的参数是测试用例的一部分,这是这个概念最精彩的部分。assumeTrue()
方法确保参数为正数,而assertEquals()
方法则检查我们需要测试的函数逻辑。
要运行上述测试用例,可以用@RunWith
注解标记该类。
@RunWith(Theories.class)
public class JunitTestsWithParameters
{
//测试用例
}
如果您认为某些测试用例在执行操作时可能会抛出异常,可以用@Rule
注解和ExpectedException
类来处理。下面给出了一个更完整的示例:
@RunWith(Theories.class)
public class JunitTestsWithParameters
{
@Rule
public ExpectedException expectedException = ExpectedException.none();
@DataPoints
public static int[][] integers()
{
return new int[][]{{1, 1}, {2, 4}, {3, 9}, {4, 16}, {5, 25}, {}};
}
@DataPoint
public static int[] input6 = new int[]{6, 36};
@DataPoint
public static int[] input7 = new int[]{7, 49};
@Theory
public void testSquares(final int[] inputs)
{
Assume.assumeTrue(inputs.length == 2);
Assume.assumeTrue(inputs[0] > 0 && inputs[1] > 0);
Assert.assertEquals(inputs[1], MathUtils.square(inputs[0]));
}
@Theory
public void testBlankArrays(final int[] inputs)
{
Assume.assumeTrue(inputs.length == 0);
expectedException.expect(ArrayIndexOutOfBoundsException.class);
Assert.assertEquals(inputs[1], MathUtils.square(inputs[0]));
}
}
但同时,您应该也注意到了,我们没有办法将一个特定的结果与一个特定的数据点相匹配。当您可以用断言的形式表达一个数据点和一个预期结果之间的一般关系,并且这种关系对所有数据都成立时,您应该使用理论。
因此,请仔细考虑理论参数化测试用例之间的选择。它们并不是参数化测试用例的确切替代品,而是与之相辅相成。