Тестирование JUnit с ожиданиями исключений (несколько утверждений)

Я тестирую WeekConverter для использования Xalan и задаюсь вопросом, что именно делает мой тест. :D

Имея следующий метод испытаний:

@Test(expected = IllegalArgumentException.class)
  public void testConvertTwoDigitYearWithWrongInput() {
  WeekConverter weekConverter = new WeekConverter(WeekConverter.Strategy.TWO_DIGIT_YEAR);

  //wrong or empty inputs
  assertEquals("0", weekConverter.convert(""));
  assertEquals("0", weekConverter.convert("abcdefgh"));
}

Ожидает ли этот тест исключение для всех утверждений или только для первого утверждения? Если бы только первое, это означало бы, что я должен создать тестовый метод для каждого утверждения, хотя я ожидаю одного и того же исключения в обоих случаях. Может ли кто-нибудь подтвердить мой пример здесь, пожалуйста?

У меня также есть тест на значение null, который выдает NullPointerException. Мягкая проверка заключается в следующем:

if (inputDate == null) {
  do something and throw NullPointerexception
} else if (inputDate.isEmpty()) {
  do something and throw IllegalArgumentException, since inputDate is not really null
} else if (inputDate.matches(regex)) {
  go futher and convert
} else {
  do something and throw IllegalArgumentException, since inputDate does not match regex
}

Поэтому один тестовый метод ожидает IllegalArgumentException с двумя утверждениями. Но очевидно, что мне нужны два разных метода тестирования не только для соблюдения функциональности JUnit, но и для того, чтобы ожидать бросок из двух разных состояний.


person Ed Michel    schedule 20.12.2011    source источник
comment
Поскольку вы ожидаете исключения, вам не нужно утверждать, что равно - все, что вам нужно, это вызов convert.   -  person avandeursen    schedule 27.12.2011


Ответы (5)


Вы можете разбить свой метод на несколько методов, но если у вас много входных выборок, это будет неудобно.

Вместо этого вы можете использовать следующий подход:

@Test
public void testConvertTwoDigitYearWithWrongInput() {
    WeekConverter weekConverter = new WeekConverter(WeekConverter.Strategy.TWO_DIGIT_YEAR); 

    assertFailsToConvert(weekConverter, ""); 
    assertFailsToConvert(weekConverter, "abcdefgh");
}

private void assertFailsToConvert(WeekConverter weekConverter, String input) {
    try {
        weekConverter.convert(input);
        fail("Should not convert [" + input + "]");
    } catch (IllegalArgumentException ex) {}
}
person axtavt    schedule 20.12.2011
comment
Проблема в том, что тесты больше не являются самодокументируемыми без просмотра теста и больше не могут быть задокументированы в удобочитаемой форме без AST и догадок. Хранение их отдельно позволяет гораздо лучше генерировать информацию. - person Dave Newton; 20.12.2011
comment
Но наличие большого количества отдельных тестов для разных входных выборок затруднило бы читабельность и удобство сопровождения, так что вам следует решить, что для вас важнее. - person axtavt; 20.12.2011

Вы должны предоставить несколько методов тестирования, поскольку они проверяют разные вещи.

Исключение будет сгенерировано в первый раз, когда преобразователь получит недопустимый аргумент.

Вы также должны проверить нулевой ввод, просто чтобы задокументировать поведение.

person Dave Newton    schedule 20.12.2011
comment
Это хороший момент... особенно при генерации одного и того же исключения, но из разных состояний. - person Ed Michel; 20.12.2011

Тест просто ожидает, что будет выброшено исключение IllegalArgumentException, независимо от того, где и почему оно было выброшено.

Я рекомендую вам разделить его на два теста.

person Victor Stafusa    schedule 20.12.2011

Вы можете поместить создание фикстуры преобразования в отдельный метод настройки @Before, а затем у вас может быть (три) отдельных тестовых примера для работы с null, "" и "abcdef".

Если нужно протестировать больше случаев, в JUnit можно использовать @Parameters и соответствующий бегун.

Ваш тестовый класс будет иметь дело только с неправильными двумя цифрами года. Его конструктор будет параметризован с помощью inputDate типа String.

Статический метод, возвращающий @Parameters, вернет коллекцию, содержащую "" и abcdefg (и другие забавные случаи).

Одиночный тестовый пример ожидает IllegalArgumentException.

@RunWith(Parameterized.class)
public class IncorrectTwoDigitYears {
    String inputDate;

    public IncorrectTwoDigitYears(String inputDate) {
        this.inputDate = inputDate;
    }

    @Test(expected = IllegalArgumentException.class)
    public void testFormat() {
        (new WeekConverter(WeekConverter.Strategy.TWO_DIGIT_YEAR))
            .convert(inputDate);
    }

    @Parameters
    public static Collection<Object[]> data() {
       Object[][] data = new Object[][] { 
           { "" }, { "abcdef" }, { "0" }, { "000" }, { "##" } };
       return Arrays.asList(data);
    }
}

Выплата будет выше, если у вас будет более двух случаев для тестирования.

person avandeursen    schedule 26.12.2011

Попробуйте catch-exception:

@Test
public void testConvertTwoDigitYearWithWrongInput() {

    WeekConverter weekConverter = ...

    // wrong or empty inputs
    verifyException(weekConverter, IllegalArgumentException.class)
       .convert("");
    verifyException(weekConverter, IllegalArgumentException.class)
       .convert("abcdefgh");
}
person rwitzel    schedule 22.06.2012