В JUnit4 вы можете писать параметризованные модульные тесты, предоставив сбор параметров в одном методе, которые будут переданы конструктору теста и тестирования в другом методе. Если у меня есть параметр, для которого я ожидаю генерирования исключения, как мне его указать?
Как проверить исключения в параметризованном тесте?
Ответы (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;
}
}
В отличие от того, что предлагают другие, я бы не стал вводить в тесты какую-либо логику - даже простые если!
У вас должно быть два метода тестирования:
- первый принимает допустимые параметры (и ожидает некоторый вывод)
- второй принимает недопустимые параметры (и ожидает исключений)
Не уверен, что JUnit с его параметризованным тестированием на основе конструктора может это сделать. Вероятно, вам придется создать два тестовых класса для этого. Используйте JUnit Params или TestNG, которые предлагают гораздо более удобное решение.
Я согласен с Томеком и пойду с двумя тестами. Первые тесты для случаев, когда исключений не ожидается. Второй проверяет значения, которые должны приводить к возникновению исключений (т. е. и терпят неудачу, если они не выбрасываются).
Ниже приведен простой пример, в котором реализация 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 для теста.
Габриэль, посмотрите правило 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"));
//...
}
Если вы использовали catch-exception вместо соответствующих аннотаций и правил JUnit4, то ваш код будет выглядеть так:
catchException(obj).method(parameter);
if (parameter != EXCEPTION_EXPECTED) {
assert caughtException() instanceof ExpectedException;
}
// more assertions
@Test(expected = Exception.class)
@Parameters(value = { "invalidInput1", "invalidInput2" })
public void shouldThrowOnInvalidInput(String input) {
ClassToTest.methodToTest(input);
}
Использование junitparams.Parameters из библиотеки junitparams.