Подтвердить что ты не робот

Как обрабатывать исключения в 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...)

4b9b3361

Ответ 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