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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4152539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 05:03:12  来源:igfitidea点击:

How do I test exceptions in a parameterized test?

javaunit-testingjunitjunit4parameterized

提问by Gabriel ??erbák

In JUnit4 you can write parameterized unit tests by providing parameters collection in one method, which will be passed to the constructor of the test and testing in another method. If I have a parameter for which I expect an exception to be thrown, how do I specify that?

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

采纳答案by Benoit Courtine

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

回答by Yarix

this is how i use junit parameterized test with expected exceptions:

这就是我如何使用带有预期异常的 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;
}
}

回答by Tomek Kaczanowski

In contrast to what other suggest, I would not introduce any kind of logic to tests - even simple ifs!

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

What you should have are two testing methods:

您应该拥有两种测试方法:

  • first one takes valid parameters (and expects some output)
  • second takes invalid parameters (and expects exceptions)
  • 第一个采用有效参数(并期望一些输出)
  • 第二个采用无效参数(并期望异常)

Not sure if JUnit with its constructor-based parametrized testing is able to do this. Probably you would have to create two test classes for this. Go with JUnit Params or TestNG which offer much more convenient solution.

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

回答by SoCal

I agree with Tomek, and would go with two tests. The first tests for cases where no exceptions are expected. The second tests for values that should result in exceptions being thrown (i.e., and fails if they are not thrown).

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

Below is a simple example, where the implementation of ExceptionThrower.throwAnInstanceException(int)simply throws an IllegalArgumentExceptionwhen the supplied int is less-than-1. In your implementation, all supplied values should trigger the exception.

下面是一个简单的例子,当提供的 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);
    });
}

If you wanted to supply multiple arguments, then you'd be looking at using a MethodSourcevice a ValueSourcefor the test.

如果您想提供多个参数,那么你会看使用MethodSource副一ValueSource进行测试。

回答by n0mer

Gabriel, please look at TestWatcher rule (since JUnit 4.9). Here is the sample code quoted from http://junit-team.github.io/junit/javadoc/4.11/org/junit/rules/TestWatcher.html:

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() {
     }
 }

Another approach would be to use ErrorCollectorfrom JUnit 4.7: @Rule public ExpectedException thrown = ExpectedException.none();

另一种方法是使用ErrorCollector从JUnit的4.7:@rule公众的ExpectedException抛出= ExpectedException.none();

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

    collector.checkThat("a", equalTo("b"));
    //...
}

回答by rwitzel

If you used catch-exceptioninstead of the corresponding annotations and rules of JUnit4, then your code would look like this:

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

catchException(obj).method(parameter);

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