4 мая 2014 г.

Тестирование исключений в JUnit

Хорошим тоном при разработке ПО считается создавать для любой исключительной ситуации в своём приложении базовое исключение и все ваши производные исключения (если таковые нужны) наследовать именно от него, а не от класса Exception. Давайте создадим такой класс.

package developer.remarks;

public class CustomException extends Exception {

public CustomException(String message) {
super(message);
}
}

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

package developer.remarks;

public class BusinessLogic {

public void doWork() throws CustomException {
throw new CustomException("произошла ошибка");
}
}

Тело метода doWork в данном случае принудительно вбрасывает исключение для наглядности примера.

А как в JUnit протестировать, что при определённых условиях ваш метод действительно выкинет CustomException? Самый простой способ - это указание ожидаемого исключения в аннотации @Test(expected = ...).

package developer.remarks;

import org.junit.Test;

public class ExceptionTest {

@Test(expected = CustomException.class)
public void testException() throws CustomException {
BusinessLogic logic = new BusinessLogic();
logic.doWork();
}
}

Обратите внимание, что в сигнатуре метода testException() обязательно нужно объявить наше исключение. Теперь тест будет считаться пройденным, если в процессе выполнения данного метода будет выброшено исключение CustomException. Также заметьте, что строки после вызова метода doWork в данном тесте выполнены не будут.

Очень хорошо, такой подход позволяет нам протестировать сам факт возникновения определённого исключения. Но как быть, если нам нужно также проверить параметры этого исключения, например, строку сообщения об ошибке? Это делается при помощи правил JUnit и класса ExpectedException (работает для JUnit, начиная с версии 4.7).

Убираем из аннотации @Test параметр expected и добавляем в тестовый класс поле expectedException с модификатором public:

@Rule
public ExpectedException expectedException = ExpectedException.none();

В итоге наш тестовый класс будет выглядеть так:

package developer.remarks;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class ExceptionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testException() throws CustomException {
expectedException.expect(CustomException.class);
expectedException.expectMessage("произошла ошибка");
BusinessLogic logic = new BusinessLogic();
logic.doWork();
}
}

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

Ну и напоследок небольшой совет, как быть, если в тексте ошибки содержится служебная информация, которую тестировать нам необязательно. Например, время возникновения ошибки ("04.05.2014 произошла ошибка"). Тогда мы можем протестировать только наличие смысловой части сообщения при помощи JUnitMatchers (т.е. наличие подстроки в сообщении):

expectedException.expectMessage(JUnitMatchers.containsString(" произошла ошибка"));

Таким образом, JUnit позволяет легко и просто тестировать не только сам факт возникновения ошибки, но и её описание.

Комментариев нет:

Отправить комментарий