Какова лучшая практика для проверки исключений в JUnit? - PullRequest
5 голосов
/ 01 сентября 2011

Я пробую свои силы в написании тестовых случаев.Из того, что я прочитал, мои тесты должны провалиться с самого начала, и я должен стремиться сделать тесты успешными.Тем не менее, я пишу тесты, проверяющие границы и исключения, которые они должны вызывать:

@Test(expected=NegativeArraySizeException.class)
public void testWorldMapIntInt() {
    WorldMap w = new WorldMap(-1, -1);
}

@Test(expected=IndexOutOfBoundsException.class)
public void testGetnIntnInt() {
    WorldMap w = new WorldMap(10,10);
    Object o = w.get(-1, -1);
}

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

Ответы [ 5 ]

3 голосов
/ 01 сентября 2011

Я согласен, что стиль, который вы представляете, не так хорош.Проблема в том, что он не проверяет , где в методе, в котором генерируется исключение, поэтому можно получить ложные отрицания.

Обычно мы пишем тесты для исключений, например:

public void testWorldMapIntInt() {
    try {
        WorldMap w = new WorldMap(-1, -1);
        Assert.fail("should have thrown IndexOutOfBoundsException");
    }
    catch (IndexOutOfBoundsException e) {}
}
2 голосов
/ 01 сентября 2011
  1. Ожидаемое поведение для WorldMap - генерировать исключение, если (-1, -1) передано в него
  2. Изначально он этого не делает, поэтому ваш тест не пройден, поскольку он не видит ожидаемого исключения.
  3. Правильно реализован код для WorldMap, включая исключение при передаче (-1, -1).
  4. Вы перезапускаете свой тест, он проходит.

Звучит как хороший TDD для меня!

1 голос
/ 01 сентября 2011

Согласитесь с принятым ответом, try-fail-catch идиома, хотя и уродливая и загромождающая тест, намного лучше, чем @Test(expcted=...), поскольку она может сообщать о ложных срабатываниях.

Некоторое время назад я реализовал очень простое правило JUnit для безопасного и удобочитаемого тестирования исключений:

public class DefaultFooServiceTest {

    @UnderTest
    private FooService fooService = new DefaultFooService();

    @Rule
    public ExceptionAssert exception = new ExceptionAssert();

    @Test
    public void shouldThrowNpeWhenNullName() throws Exception {
        //given
        String name = null;

        //when
        fooService.echo(name);

        //then
        exception.expect(NullPointerException.class);
    }

    @Test
    public void shouldThrowIllegalArgumentWhenNameJohn() throws Exception {
        //given
        String name = "John";

        //when
        fooService.echo(name);

        //then
        exception.expect(IllegalArgumentException.class)
                .expectMessage("Name: 'John' is not allowed");
    }
}

См. сообщение в блоге и источник .

1 голос
/ 01 сентября 2011

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

Что касается того, что этот тест не пройден по умолчанию, я не могу придумать разумного способа сделать это, если вы хотите, чтобы он действительно что-то делал (если вы пишете тесты вначале, то он должен потерпеть неудачу, потому что конструкторне будет никакого кода).

1 голос
/ 01 сентября 2011

Это похоже на честный тест для написания.WorldMap не является стандартным классом Java.Предположительно это твой собственный класс.Поэтому тест не прошел бы, если бы вы еще не написали некоторый код.Этот тест заставит вас выбросить (или распространить) соответствующее исключение из вашего класса.Для меня это звучит как хороший тест, который вы должны написать перед реализацией поведения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...