23

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

4

7 回答 7

30

这就是我使用带有预期异常的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;
}
}
于 2016-03-27T13:13:10.100 回答
8

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

你应该有两种测试方法:

  • 第一个采用有效参数(并期望一些输出)
  • second 采用无效参数(并期望异常)

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

于 2012-09-20T18:48:55.523 回答
7

我同意 Tomek 的观点,并会进行两次测试。第一个测试预期没有异常的情况。第二个测试应该导致抛出异常的值(即,如果不抛出异常则失败)。

下面是一个简单的示例,当提供的 int 小于 1 时, ExceptionThrower.throwAnInstanceException(int)的实现只是简单地抛出一个IllegalArgumentException 。在您的实现中,所有提供的值都应该触发异常。

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

    assertThrows(IllegalArgumentException.class, () -> {
        exceptionThrower.throwAnInstanceException(testValue);
    });
}

如果您想提供多个参数,那么您将考虑使用MethodSourceValueSource进行测试。

于 2018-09-26T20:52:06.207 回答
5
if (parameter == EXCEPTION_EXPECTED) {
    try {
        method(parameter);
        fail("didn't throw an exception!");
    } catch (ExpectedException ee) {
        // Test succeded!
    }
}
于 2010-11-11T08:33:37.280 回答
1

Gabriel,请查看 TestWatcher 规则(自 JUnit 4.9 起)。这是从http://junit-team.github.io/junit/javadoc/4.11/org/junit/rules/TestWatcher.html引用的示例代码:

public static class WatchmanTest {
    private static String watchedLog;

    @Rule
    public TestWatcher watchman= new TestWatcher() {
        @Override
        protected void failed(Throwable e, Description description) {
            watchedLog+= description + "\n";
        }

        @Override
        protected void succeeded(Description description) {
            watchedLog+= description + " " + "success!\n";
        }
     };


     @Test
     public void fails() {
         fail();
     }

     @Test
     public void succeeds() {
     }
 }

另一种方法是使用JUnit 4.7 中的ErrorCollector:@Rule public ExpectedException throw = ExpectedException.none();

@Test
public void testCollectingErrors() {
    thrown.handleAssertionErrors();
    thrown.expect(MultipleFailureException.class); // or #expectMessage()/#expectCause()

    collector.checkThat("a", equalTo("b"));
    //...
}
于 2014-07-02T04:45:19.553 回答
0

如果您使用catch-exception而不是 JUnit4 的相应注释和规则,那么您的代码将如下所示:

catchException(obj).method(parameter);

if (parameter != EXCEPTION_EXPECTED) {
    assert caughtException() instanceof ExpectedException;
}
// more assertions
于 2012-06-22T17:26:33.857 回答
0
@Test(expected = Exception.class)
@Parameters(value = { "invalidInput1", "invalidInput2" })
public void shouldThrowOnInvalidInput(String input) {
    ClassToTest.methodToTest(input);
}

使用 junitparams中的 junitparams.Parameters 。

于 2020-07-14T09:06:59.233 回答