Перейти к основному содержимому

Строгая заглушка Mockito и исключение UnnecessaryStubbingException

· 4 мин. чтения

1. Обзор

В этом кратком руководстве мы узнаем об исключении Mockito UnnecessaryStubbingException . Это исключение является распространенным исключением, с которым мы, вероятно, столкнемся при неправильном использовании заглушек.

Мы начнем с объяснения философии строгой заглушки и того, почему Mockito поощряет ее использование по умолчанию. Затем мы рассмотрим, что именно означает это исключение и при каких обстоятельствах оно может возникнуть. Наконец, мы увидим пример того, как мы можем подавить это исключение в наших тестах.

Чтобы узнать больше о тестировании с помощью Mockito, ознакомьтесь с нашей обширной серией статей о Mockito .

2. Строгая заглушка

В версии 1.x Mockito можно было настраивать макеты и взаимодействовать с ними без ограничений. Это означало, что со временем тесты часто становились слишком сложными, а временами их было труднее отлаживать.

Начиная с версии 2.+ Mockito вводит новые функции, которые подталкивают фреймворк к «строгости». Основные цели, стоящие за этим:

  • Обнаружение неиспользуемых заглушек в тестовом коде
  • Уменьшите дублирование тестового кода и ненужный тестовый код
  • Продвигайте более чистые тесты, удаляя «мертвый» код
  • Помогите улучшить отладку и производительность

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

Подводя итог, можно сказать, что строгая заглушка сообщает о ненужных заглушках, обнаруживает несоответствие аргументов заглушки и делает наши тесты более СУХИМИ (не повторяйтесь). Это облегчает чистую и поддерживаемую кодовую базу.

2.1. Настройка строгих заглушек

Начиная с Mockito 2.+, строгая заглушка используется по умолчанию при инициализации наших макетов с помощью:

  • MockitoJUnitRunner
  • MockitoJUnit.rule()

Mockito настоятельно рекомендует использовать любой из вышеперечисленных способов . Однако есть еще один способ включить строгую заглушку в наших тестах, когда мы не используем правило или бегун Mockito:

Mockito.mockitoSession()
.initMocks(this)
.strictness(Strictness.STRICT_STUBS)
.startMocking();

И последнее важное замечание: в Mockito 3.0 все заглушки будут «строгими» и проверенными по умолчанию.

3. Пример ненужного исключения StubbbingException

Проще говоря, ненужная заглушка — это заглушенный вызов метода, который так и не был реализован во время выполнения теста.

Давайте рассмотрим простой пример:

@Test
public void givenUnusedStub_whenInvokingGetThenThrowUnnecessaryStubbingException() {
when(mockList.add("one")).thenReturn(true); // this won't get called
when(mockList.get(anyInt())).thenReturn("hello");
assertEquals("List should contain hello", "hello", mockList.get(1));
}

Когда мы запустим этот модульный тест, Mockito обнаружит неиспользуемую заглушку и выдаст исключение UnnecessaryStubbingException :

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at com.foreach.mockito.misusing.MockitoUnecessaryStubUnitTest.givenUnusedStub_whenInvokingGetThenThrowUnnecessaryStubbingException(MockitoUnecessaryStubUnitTest.java:37)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.

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

Почему это происходит? Ну, во-первых, когда вызов настраивает наш макет так, чтобы он возвращал true , когда мы вызываем метод добавления с аргументом «один». Однако затем мы не вызываем этот метод во время выполнения остальной части модульного теста.

Mockito говорит нам, что наша первая строка when избыточна, и, возможно, мы допустили ошибку при настройке наших заглушек.

Хотя этот пример тривиален, при моделировании сложной иерархии объектов легко представить, как такого рода сообщения могут помочь в отладке и быть очень полезными в других отношениях.

4. Обход строгой заглушки

Наконец, давайте посмотрим, как обойти строгие заглушки. Это также известно как снисходительное заглушение.

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

@Test
public void givenLenientdStub_whenInvokingGetThenThrowUnnecessaryStubbingException() {
lenient().when(mockList.add("one")).thenReturn(true);
when(mockList.get(anyInt())).thenReturn("hello");
assertEquals("List should contain hello", "hello", mockList.get(1));
}

В приведенном выше примере мы используем статический метод Mockito.lenient() , чтобы включить снисходительную заглушку в методе добавления нашего фиктивного списка.

Мягкие заглушки обходят правила проверки «строгих заглушек». Например, если заглушка объявлена как мягкая, она не будет проверяться на возможные проблемы с заглушкой, такие как ненужная заглушка, описанная ранее.

5. Вывод

В этой краткой статье мы представили концепцию строгой заглушки в Mockito, подробно описав философию, почему она была введена и почему это важно.

Затем мы рассмотрели пример UnnecessaryStubbingException, прежде чем закончить примером того, как включить мягкое заглушение в наших тестах.

Как всегда, полный исходный код статьи доступен на GitHub .