Java 如何在参数化测试中测试异常?

Java 如何在参数化测试中测试异常?,java,unit-testing,junit,junit4,parameterized,Java,Unit Testing,Junit,Junit4,Parameterized,在JUnit4中,您可以通过在一个方法中提供参数集合来编写参数化单元测试,参数集合将传递给测试的构造函数,并在另一个方法中进行测试。如果我有一个期望引发异常的参数,如何指定该参数?如果您使用JUnit4的注释和规则来代替相应的注释和规则,那么您的代码如下所示: if (parameter == EXCEPTION_EXPECTED) { try { method(parameter); fail("didn't throw an exception!");

在JUnit4中,您可以通过在一个方法中提供参数集合来编写参数化单元测试,参数集合将传递给测试的构造函数,并在另一个方法中进行测试。如果我有一个期望引发异常的参数,如何指定该参数?

如果您使用JUnit4的注释和规则来代替相应的注释和规则,那么您的代码如下所示:

if (parameter == EXCEPTION_EXPECTED) {
    try {
        method(parameter);
        fail("didn't throw an exception!");
    } catch (ExpectedException ee) {
        // Test succeded!
    }
}
catchException(obj).method(parameter);

if (parameter != EXCEPTION_EXPECTED) {
    assert caughtException() instanceof ExpectedException;
}
// more assertions

与其他人的建议相反,我不会在测试中引入任何逻辑——即使是简单的ifs

您应该有两种测试方法:

  • 第一个接受有效参数(并期望一些输出)
  • 第二个接受无效参数(并期望异常)

不确定JUnit及其基于构造函数的参数化测试是否能够做到这一点。可能您必须为此创建两个测试类。使用JUnit参数或TestNG,它们提供了更方便的解决方案。

Gabriel,请查看TestWatcher规则(从JUnit 4.9开始)。以下是引用的示例代码:

另一种方法是使用JUnit 4.7: @统治 抛出公共ExpectedException=ExpectedException.none()


以下是我如何在预期的异常情况下使用junit参数化测试:

@RunWith(Parameterized.class)
public class CalcDivTest {

@Parameter(0)
public int num1;
@Parameter(1)
public int num2;

@Parameter(2)
public int expectedResult;

@Parameter(3)
public Class<? extends Exception> expectedException;
@Parameter(4)
public String expectedExceptionMsg;

@Rule
public ExpectedException thrown = ExpectedException.none();

@Parameters
public static Iterable<Object[]> data() {
    return Arrays.asList(new Object[][] {
        // calculation scenarios:
        { 120, 10, 12, null, null }, // simple div  
        { 120, 0, -1, ArithmeticException.class, "/ by zero" }, // div by zero          
    });

}

@Test
public void testDiv() throws CCalculationException {

    //setup expected exception
    if (expectedException != null) {
        thrown.expect(expectedException);
        thrown.expectMessage(expectedExceptionMsg);
    }

    assertEquals("calculation result is not as", expectedResult, div(num1, num2) );

}

private int div(int a, int b) {
    return a/b;
}
}
@RunWith(参数化的.class)
公共类CalcDivTest{
@参数(0)
公共int num1;
@参数(1)
公共国际单位m2;
@参数(2)
公众期望结果;
@参数(3)

公共类我同意托梅克的观点,并将进行两项测试。第一项测试用于预期不会出现异常的情况。第二项测试用于应导致抛出异常的值(即,如果没有抛出异常,则会失败)

下面是一个简单的示例,其中ExceptionRower.throwAnInstanceException(int)的实现仅在提供的int小于-1时引发IllegalArgumentException。在您的实现中,所有提供的值都应触发异常

@ParameterizedTest
@ValueSource(ints = {0, 1})
public void parameterizedIntExceptionTest(int testValue) {
    ExceptionThrower exceptionThrower = new ExceptionThrower();

    assertThrows(IllegalArgumentException.class, () -> {
        exceptionThrower.throwAnInstanceException(testValue);
    });
}
如果您想提供多个参数,那么您应该考虑使用MethodSource,而不是ValueSource进行测试

@Test(expected = Exception.class)
@Parameters(value = { "invalidInput1", "invalidInput2" })
public void shouldThrowOnInvalidInput(String input) {
    ClassToTest.methodToTest(input);
}

使用junitparams.Parameters from library。

我希望有一个更合理的解决方案-例如,类似于带有可选预期注释参数的多个@Parameters方法,但我想这不是框架的一部分。无论如何,谢谢。在测试用例中使用try-catch不是实现这一点的最佳方法。我会选择t@Yarix的回答。
@ParameterizedTest
@ValueSource(ints = {0, 1})
public void parameterizedIntExceptionTest(int testValue) {
    ExceptionThrower exceptionThrower = new ExceptionThrower();

    assertThrows(IllegalArgumentException.class, () -> {
        exceptionThrower.throwAnInstanceException(testValue);
    });
}
@Test(expected = Exception.class)
@Parameters(value = { "invalidInput1", "invalidInput2" })
public void shouldThrowOnInvalidInput(String input) {
    ClassToTest.methodToTest(input);
}