Как обрабатывать исключения в junit
Я написал несколько тестовых примеров для тестирования некоторого метода. Но некоторые методы вызывают исключение. Правильно ли я делаю это?
private void testNumber(String word, int number) {
try {
assertEquals(word, service.convert(number));
} catch (OutOfRangeNumberException e) {
Assert.fail("Test failed : " + e.getMessage());
}
}
@Test
public final void testZero() {
testNumber("zero", 0);
}
Если я пройду -45
, он потерпит неудачу с OutOfRangeException
, но я не могу проверить конкретное исключение, например @Test(Expected...)
Ответы
Ответ 1
Неопределенное исключение - это сбой теста, поэтому вам не нужно и не хотите его улавливать.
@Test
public void canConvertStringsToDecimals() {
String str = "1.234";
Assert.assertEquals(1.234, service.convert(str), 1.0e-4);
}
Пока service
не бросает IllegalArgumentException
, потому что str
имеет десятичную точку в нем, это будет простой сбой теста.
Ожидаемое исключение должно обрабатываться необязательным аргументом expected
@Test
.
@Test(expected=NullPointerException.class)
public void cannotConvertNulls() {
service.convert(null);
}
Если программист ленился и бросил Exception
, или если у него service
return 0.0
, тест завершится с ошибкой. Только NPE
будет успешным. Обратите внимание, что также работают подклассы ожидаемого исключения. Это редкость для NPE
s, но обычно с IOException
и SQLException
s.
В редком случае, когда вы хотите протестировать конкретное сообщение об исключении, вы используете новый ExpectedException
JUnit @Rule
.
@Rule
public ExpectedException thrown= ExpectedException.none();
@Test
public void messageIncludesErrantTemperature() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("-400"); // Tests that the message contains -400.
temperatureGauge.setTemperature(-400);
}
Теперь, если setTemperature выбрасывает IAE
, а сообщение содержит температуру, которую пользователь пытался установить, тест терпит неудачу. Это правило может использоваться более сложными способами.
Ваш пример лучше всего обрабатывать:
private void testNumber(String word, int number)
throws OutOfRangeNumberException {
assertEquals(word, service.convert(number));
}
@Test
public final void testZero()
throws OutOfRangeNumberException {
testNumber("zero", 0);
}
Вы можете встроить testNumber
; теперь это мало помогает. Вы можете превратить это в параметризованный тестовый класс.
Ответ 2
Удалите блок try-catch и добавьте throws Exception
к вашему тестовому методу, например:
@Test
public final void testZero() throws Exception {
assertEquals("zero", service.convert(0));
}
JUnit ожидает, что неудачные тесты будут генерировать исключения, ваш захват просто прекращает JUnit от возможности сообщать о них должным образом. Также этот способ будет работать с ожидаемым свойством в аннотации @Test.
Ответ 3
Вам не нужно ловить исключение, чтобы не выполнить тест. Просто отпустите его (объявив throws
), и он все равно потерпит неудачу.
Другим случаем является то, что вы действительно ожидаете исключение, тогда вы ставите неудачу в конце блока try.
Например:
@Test
public void testInvalidNumber() {
try {
String dummy = service.convert(-1));
Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.")
} catch (OutOfRangeException e) {
// expected
}
}
Вы можете использовать этот тип теста, чтобы проверить, правильно ли ваш код проверяет ввод и обрабатывает недопустимый ввод с правильным исключением.
Ответ 4
Существует несколько стратегий, которые открыты для вас, чтобы иметь дело с ожидаемыми исключениями в ваших тестах. Я думаю, что аннотации JUnit и идиома try/catch уже упоминались выше. Я хотел бы обратить внимание на вариант Java 8 для выражений лямбда.
Например:
class DummyService {
public void someMethod() {
throw new RuntimeException("Runtime exception occurred");
}
public void someOtherMethod(boolean b) {
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
}
Вы можете сделать это:
@Test
public void verifiesCauseType() {
// lambda expression
assertThrown(() -> new DummyService().someOtherMethod(true))
// assertions
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasCauseInstanceOf(IllegalStateException.class);
}
Взгляните на этот блог, который охватывает большинство вариантов с примерами.
http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html
И этот вариант более подробно объясняет вариант Java 8 Lambda:
http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html