Mockito-Java8 — это набор дополнений Mockito, использующих Java 8 и лямбда-выражения, которые делают Mockito еще более компактным.
В начале 2015 года я выступил с докладом по флеш-памяти. Java 8 дает возможность тестировать! на GeeCON TDD 2015 и DevConf.cz 2015. В своей речи на 4 примерах я показал, как Java 8, а именно лямбда-выражения, может упростить инструменты тестирования и тестирования в целом. Одним из таких инструментов был Mokcito. Чтобы не позволить моему PoC-коду умереть на слайдах и сделать его просто доступным для других, я выпустил небольшой проект с двумя полезными в указанном случае дополнениями Java 8 для Mockito.
Быстрое введение
В качестве предпосылки предположим, что у нас есть следующая структура данных:
|
1
2
3
4
5
|
@Immutableclass ShipSearchCriteria { int minimumRange; int numberOfPhasers;} |
Библиотека предоставляет два дополнения:
Lambda matcher — позволяет определить логику соответствия в лямбда-выражении.
|
1
2
|
given(ts.findNumberOfShipsInRangeByCriteria( argLambda(sc -> sc.getMinimumRange() > 1000))).willReturn(4); |
Argument Captor — Java 8 edition — позволяет использовать ArgumentCaptor в одну строку (здесь с AssertJ):
|
1
2
|
verify(ts).findNumberOfShipsInRangeByCriteria( assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000))); |
Лямбда-матчер
С помощью статического метода argLambda создается экземпляр лямбда-сопоставителя, который можно использовать для определения логики сопоставления в лямбда-выражении (здесь для заглушки). Это может быть особенно полезно при работе со сложными классами, передаваемыми в качестве аргумента.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
@Testpublic void shouldAllowToUseLambdaInStubbing() { //given given(ts.findNumberOfShipsInRangeByCriteria( argLambda(sc -> sc.getMinimumRange() > 1000))).willReturn(4); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(1500, 2))).isEqualTo(4); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(700, 2))).isEqualTo(0);} |
Для сравнения та же логика, реализованная с пользовательским Ответом в Java 7:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Testpublic void stubbingWithCustomAsnwerShouldBeLonger() { //old way //given given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); ShipSearchCriteria criteria = (ShipSearchCriteria) args[0]; if (criteria.getMinimumRange() > 1000) { return 4; } else { return 0; } } }); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(1500, 2))).isEqualTo(4); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(700, 2))).isEqualTo(0);} |
Даже Java 8 и менее читаемые конструкции не слишком помогают:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Testpublic void stubbingWithCustomAsnwerShouldBeLongerEvenAsLambda() { //old way //given given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(invocation -> { ShipSearchCriteria criteria = (ShipSearchCriteria) invocation.getArguments()[0]; return criteria.getMinimumRange() > 1000 ? 4 : 0; }); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(1500, 2))).isEqualTo(4); //expect assertThat(ts.findNumberOfShipsInRangeByCriteria( new ShipSearchCriteria(700, 2))).isEqualTo(0);} |
Аргумент Captor — Java 8 издание
Статический метод assertArg создает сопоставление аргументов, реализация которого внутренне использует ArgumentMatcher с утверждением, предоставленным в лямбда-выражении. В приведенном ниже примере AssertJ предоставляет значимое сообщение об ошибке, но можно использовать любые утверждения (например, native от TestNG или JUnit) (если это действительно необходимо). Это позволяет встроить ArgumentCaptor:
|
1
2
3
4
5
6
7
8
|
@Testpublic void shouldAllowToUseAssertionInLambda() { //when ts.findNumberOfShipsInRangeByCriteria(searchCriteria); //then verify(ts).findNumberOfShipsInRangeByCriteria( assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000)));} |
По сравнению с 3 линиями классическим способом:
|
01
02
03
04
05
06
07
08
09
10
|
@Testpublic void shouldAllowToUseArgumentCaptorInClassicWay() { //old way //when ts.findNumberOfShipsInRangeByCriteria(searchCriteria); //then ArgumentCaptor<ShipSearchCriteria> captor = ArgumentCaptor.forClass(ShipSearchCriteria.class); verify(ts).findNumberOfShipsInRangeByCriteria(captor.capture()); assertThat(captor.getValue().getMinimumRange()).isLessThan(2000);} |
Резюме
Представленные дополнения были созданы как PoC для моей речи на конференции, но должны быть полностью функциональными и потенциально полезными в конкретных случаях. Чтобы использовать его в своем проекте, достаточно использовать Mockito 1.10.x или 2.0.x-beta, добавить mockito-java8 в качестве зависимости и, конечно же, скомпилировать ваш проект с Java 8+.
- Более подробная информация доступна на веб-странице проекта: https://github.com/szpak/mockito-java8
| Ссылка: | Более компактный Mockito с Java 8, лямбда-выражениями и надстройками Mockito-Java8 от нашего партнера по JCG Марцина Заячковского в блоге Solid Soft . |