Как проверить исключения в параметризованном тесте?

В JUnit4 вы можете писать параметризованные модульные тесты, предоставив сбор параметров в одном методе, которые будут переданы конструктору теста и тестирования в другом методе. Если у меня есть параметр, для которого я ожидаю генерирования исключения, как мне его указать?


person Gabriel Ščerbák    schedule 11.11.2010    source источник


Ответы (7)


вот как я использую параметризованный тест 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;
}
}
person Yarix    schedule 27.03.2016

В отличие от того, что предлагают другие, я бы не стал вводить в тесты какую-либо логику - даже простые если!

У вас должно быть два метода тестирования:

  • первый принимает допустимые параметры (и ожидает некоторый вывод)
  • второй принимает недопустимые параметры (и ожидает исключений)

Не уверен, что JUnit с его параметризованным тестированием на основе конструктора может это сделать. Вероятно, вам придется создать два тестовых класса для этого. Используйте JUnit Params или TestNG, которые предлагают гораздо более удобное решение.

person Tomek Kaczanowski    schedule 20.09.2012

Я согласен с Томеком и пойду с двумя тестами. Первые тесты для случаев, когда исключений не ожидается. Второй проверяет значения, которые должны приводить к возникновению исключений (т. е. и терпят неудачу, если они не выбрасываются).

Ниже приведен простой пример, в котором реализация ExceptionThrower.throwAnInstanceException(int) просто создает исключение IllegalArgumentException, когда указанное значение int меньше 1. В вашей реализации все предоставленные значения должны вызывать исключение.

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

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

Если вы хотите указать несколько аргументов, вам следует использовать MethodSource вместо ValueSource для теста.

person SoCal    schedule 26.09.2018

Габриэль, посмотрите правило 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() {
     }
 }

Другим подходом может быть использование ErrorCollector из JUnit 4.7: @Rule public ExpectedException throwed = ExpectedException.none();

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

    collector.checkThat("a", equalTo("b"));
    //...
}
person n0mer    schedule 02.07.2014

Если вы использовали catch-exception вместо соответствующих аннотаций и правил JUnit4, то ваш код будет выглядеть так:

catchException(obj).method(parameter);

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

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

Использование junitparams.Parameters из библиотеки junitparams.

person embuc    schedule 14.07.2020

person    schedule
comment
Я надеялся на более разумное решение - например. что-то вроде нескольких методов @Parameters с необязательным ожидаемым аргументом аннотации, но я предполагаю, что что-то подобное не является частью фреймворка. Все равно спасибо. - person Gabriel Ščerbák; 11.11.2010
comment
Использование try-catch в тестовом примере — не лучший способ добиться этого. Я бы выбрал ответ @Yarix. - person ehsun7b; 09.05.2019