Есть много способов обработки исключений в JUnit ( 3 способа обработки исключений в JUnit. Какой из них выбрать?, Правило JUnit ExpectedException: помимо основ ). В этой статье я представлю библиотеку catch-exception, которую мне рекомендовали попробовать. Короче говоря, catch-exception — это библиотека, которая перехватывает исключения в одной строке кода и делает их доступными для дальнейшего анализа.
Установить через Maven
Чтобы быстро начать работу, я использовал свой демонстрационный проект Unit Testing с набором тестовых зависимостей ( JUnit, Mocito, Hamcrest, AssertJ ) и добавил исключения- ловушки :
1
2
3
4
5
6
|
< dependency > < groupId >com.googlecode.catch-exception</ groupId > < artifactId >catch-exception</ artifactId > < version >1.2.0</ version > < scope >test</ scope > </ dependency > |
Таким образом, дерево зависимостей выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
[INFO] --- maven-dependency-plugin: 2.1 :tree @ unit-testing-demo --- [INFO] com.github.kolorobot:unit-testing-demo:jar: 1.0 . 0 -SNAPSHOT [INFO] +- org.slf4j:slf4j-api:jar: 1.5 . 10 :compile [INFO] +- org.slf4j:jcl-over-slf4j:jar: 1.5 . 10 :runtime [INFO] +- org.slf4j:slf4j-log4j12:jar: 1.5 . 10 :runtime [INFO] +- log4j:log4j:jar: 1.2 . 15 :runtime [INFO] +- junit:junit:jar: 4.11 :test [INFO] +- org.mockito:mockito-core:jar: 1.9 . 5 :test [INFO] +- org.assertj:assertj-core:jar: 1.5 . 0 :test [INFO] +- org.hamcrest:hamcrest-core:jar: 1.3 :test [INFO] +- org.hamcrest:hamcrest-library:jar: 1.3 :test [INFO] +- org.objenesis:objenesis:jar: 1.3 :test [INFO] \- com.googlecode. catch -exception: catch -exception:jar: 1.2 . 0 :test |
Начиная
Тестируемая система (SUT):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
class ExceptionThrower { void someMethod() { throw new RuntimeException( "Runtime exception occurred" ); } void someOtherMethod() { throw new RuntimeException( "Runtime exception occurred" , new IllegalStateException( "Illegal state" )); } void yetAnotherMethod( int code) { throw new CustomException(code); } } |
Пример базового подхода в стиле BDD для ловли с исключениями AssertJ :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
import org.junit.Test; import static com.googlecode.catchexception.CatchException.*; import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.*; public class CatchExceptionsTest { @Test public void verifiesTypeAndMessage() { when( new SomeClass()).someMethod(); then(caughtException()) .isInstanceOf(RuntimeException. class ) .hasMessage( "Runtime exception occurred" ) .hasMessageStartingWith( "Runtime" ) .hasMessageEndingWith( "occured" ) .hasMessageContaining( "exception" ) .hasNoCause(); } } |
Выглядит неплохо. Кратко, читабельно. Нет бегунов JUnit. Обратите внимание, что я указал, какой метод SomeClass
я ожидаю, чтобы SomeClass
исключение. Как вы можете себе представить, я могу проверить несколько исключений в одном тесте. Хотя я бы не рекомендовал такой подход, так как может показаться, что он нарушает одну обязанность теста.
Кстати, если вы работаете с Eclipse, это может быть полезно для вас: улучшите поддержку содержимого для типов со статическими членами при создании тестов JUnit в Eclipse
Проверьте причину
Я думаю, что нет никакого комментария, необходимого для приведенного ниже кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
import org.junit.Test; import static com.googlecode.catchexception.CatchException.*; import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.*; public class CatchExceptionsTest { @Test public void verifiesCauseType() { when( new ExceptionThrower()).someOtherMethod(); then(caughtException()) .isInstanceOf(RuntimeException. class ) .hasMessage( "Runtime exception occurred" ) .hasCauseExactlyInstanceOf(IllegalStateException. class ) .hasRootCauseExactlyInstanceOf(IllegalStateException. class ); } } |
Проверьте пользовательское исключение с Hamcrest
Для проверки пользовательского исключения я использовал код соответствия Hamcrest из моего предыдущего поста :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
class CustomException extends RuntimeException { private final int code; public CustomException( int code) { this .code = code; } public int getCode() { return code; } } class ExceptionCodeMatches extends TypeSafeMatcher<CustomException> { private int expectedCode; public ExceptionCodeMatches( int expectedCode) { this .expectedCode = expectedCode; } @Override protected boolean matchesSafely(CustomException item) { return item.getCode() == expectedCode; } @Override public void describeTo(Description description) { description.appendText( "expects code " ) .appendValue(expectedCode); } @Override protected void describeMismatchSafely(CustomException item, Description mismatchDescription) { mismatchDescription.appendText( "was " ) .appendValue(item.getCode()); } } |
И тест:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
import org.junit.Test; import static com.googlecode.catchexception.CatchException.*; import static org.junit.Assert.*; public class CatchExceptionsTest { @Test public void verifiesCustomException() { catchException( new ExceptionThrower(), CustomException. class ).yetAnotherMethod( 500 ); assertThat((CustomException) caughtException(), new ExceptionCodeMatcher( 500 )); } } |
Резюме
ловушка-исключение выглядит действительно хорошо. Это легко начать быстро. Я вижу некоторые преимущества по сравнению с правилом метода в JUnit. Если у меня будет возможность, я буду более тщательно исследовать библиотеку, надеюсь, в реальном проекте.
- Исходный код этой статьи можно найти здесь: Демонстрация модульного тестирования
В случае, если вы заинтересованы, пожалуйста, посмотрите на мои другие сообщения:
- 3 способа обработки исключений в JUnit. Какой выбрать?
- Правило JUnit ExpectedException: вне основ
- Как: проверить зависимости в проекте Maven (JUnit, Mocito, Hamcrest, AssertJ)
- Улучшение поддержки содержимого для типов со статическими членами при создании тестов JUnit в Eclipse
Ссылка: | Еще один способ обработки исключений в JUnit: catch-исключение от нашего партнера по JCG Рафаля Боровца из блога Codeleak.pl . |