Как в JUnit проверить, что метод выбрасывает определённое исключение?
Основные способы проверки исключений в JUnit 4
Проблема, с которой вы столкнулись, классическая для начинающих. Когда исключение выбрасывается внутри теста, JUnit по умолчанию считает это ошибкой. Чтобы сказать JUnit: "Нет, это ожидаемое поведение", нужно использовать специальные механизмы. Рассмотрим три основных подхода.
1. Атрибут expected в @Test (самый простой)
Самый лаконичный способ — указать ожидаемое исключение прямо в аннотации:
@Test(expected = IllegalArgumentException.class)
public void testDivideByZero() {
Calculator calc = new Calculator();
calc.divide(10, 0);
}
Если метод выбросит IllegalArgumentException, тест пройдёт. Если выбросит другое исключение (например, ArithmeticException) или не выбросит ничего — тест упадёт. Минус: нельзя проверить сообщение исключения.
2. Блок try-catch с assert (гибкий, но громоздкий)
Классический способ из JUnit 3, который работает и в JUnit 4:
@Test
public void testDivideByZero() {
Calculator calc = new Calculator();
try {
calc.divide(10, 0);
fail("Ожидалось IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertEquals("Делитель не может быть нулём", e.getMessage());
}
}
Здесь мы явно ловим исключение и проверяем его сообщение. Если метод не выбросил исключение, выполняется fail() — тест падает. Если выбросил не тот тип — исключение улетит выше и тест тоже упадёт.
3. Правило ExpectedException (JUnit 4.7+)
Более элегантный способ с правилами:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class CalculatorTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testDivideByZero() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Делитель не может быть нулём");
Calculator calc = new Calculator();
calc.divide(10, 0);
}
}
Правило ExpectedException позволяет проверить и тип, и сообщение. Важно: вызов expect() должен быть до вызова тестируемого метода. Можно проверять также причину (expectCause()) и использовать матчеры Hamcrest для более сложных проверок сообщения (например, expectMessage(startsWith("Делитель"))).
Рекомендации
- Для простой проверки типа исключения используйте
@Test(expected=...)— это минималистично и читаемо. - Если нужно проверить сообщение или другие детали, используйте
ExpectedException(илиassertThrowsиз JUnit 5, если перейдёте на новую версию). - Избегайте пустых catch-блоков — это скрывает ошибки.
- Помните: тест должен проверять только одно исключение. Если в методе несколько точек выброса, пишите отдельные тесты для каждой.
В JUnit 5 (Jupiter) появился метод assertThrows, который делает то же самое ещё проще:
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void testDivideByZero() {
Calculator calc = new Calculator();
IllegalArgumentException exception = assertThrows(
IllegalArgumentException.class,
() -> calc.divide(10, 0)
);
assertEquals("Делитель не может быть нулём", exception.getMessage());
}
Но это уже для JUnit 5, а вы, судя по вопросу, используете JUnit 4.
<<Альтернативный подход: JUnit 5 (Jupiter) с assertThrows
Если у вас есть возможность перейти на JUnit 5, я настоятельно рекомендую использовать встроенный метод assertThrows. Он решает все проблемы JUnit 4 в одном флаконе:
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Test
void testDivideByZero() {
Calculator calc = new Calculator();
// Проверяем, что исключение выбрасывается, и получаем его
IllegalArgumentException exception = assertThrows(
IllegalArgumentException.class,
() -> calc.divide(10, 0)
);
// Дополнительно проверяем сообщение
assertEquals("Делитель не может быть нулём", exception.getMessage());
}
Преимущества:
- Не нужно использовать
@Ruleили блоки try-catch. - Лямбда-выражение делает код компактным.
- Можно проверить любое количество свойств исключения.
- Метод возвращает сам объект исключения для дальнейших проверок.
Если вы пишете новый проект или можете обновить зависимости, мигрируйте на JUnit 5. Это упростит тестирование не только исключений, но и многих других сценариев. В JUnit 4 же лучшим выбором остаётся ExpectedException или @Test(expected=...) для простых случаев.
Ответов пока нет.
Войдите чтобы оставить ответ