Статьи

Mockito — лучшие сообщения об ошибках в NPE с глобально настроенным SmartNull

При написании справочной карты Mockito у меня была возможность познакомиться с менее популярными, но очень полезными функциями Mockito. Некоторые из них были слишком заблаговременными или слишком редкими в использовании, чтобы их можно было описать в рефкарте, которая должна быть короткой. Одной из таких вещей является SmartNull. В настоящее время не void методы возвращают «безопасное пустое значение», подходящее для известных типов (например, 0, false, пустая коллекция) или null в других случаях. SmartNull может быть возвращен вместо чистого нуля, чтобы получить гораздо более описательное сообщение об ошибке в NPE.

Вместо строки, когда произошло исключение NullPointerException:

1
2
3
java.lang.NullPointerException
    at PlantWaterer.generateNPE(PlantWaterer.java:24)
    at DefaultValuesTest.shouldReturnNicerErrorMessageOnNPE(DefaultValuesTest.java:64)

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

1
2
3
4
5
6
7
8
9
org.mockito.exceptions.verification.SmartNullPointerException:
You have a NullPointerException here:
?> at PlantWaterer.generateNPE(PlantWaterer.java: 24)
because this method call was ?not? stubbed correctly:
?> at PlantWaterer.generateNPE(PlantWaterer.java: 24)
wateringScheduler.returnNull();
 
    at PlantWaterer.generateNPE(PlantWaterer.java: 24)
    at DefaultValuesTest.shouldReturnNicerErrorMessageOnNPE(DefaultValuesTest.java:64)

Конкретный макет может быть проинструктирован возвращать SmartNull вместо нулевого значения:

1
2
PlantWaterer plantWatererMock =
        mock(PlantWaterer.class, Mockito.RETURNS_SMART_NULLS);

или же

1
2
@Mock(answer = Answers.RETURNS_SMART_NULLS)
private PlantWaterer plantWatererMock;

SmartNull, вероятно, будет поведением по умолчанию в Mockito 2.0, но для обратной совместимости в 1.9.x необходимо явно указывать каждому макету использовать его. Необходимость написания еще одного стандартного кода приводит к тому, что почти никто не использует SmartNull, несмотря на то, что это очень полезная функция. И там в игру вступает второй почти неизвестный элемент Mockito — глобальная конфигурация. Как правило, нет необходимости настраивать Mockito. Это просто работает. Но в некоторых редких случаях авторы фреймворка оставили шлюз, который позволяет переопределить конфигурацию по умолчанию для нескольких основных вариантов поведения, включая политику ответов по умолчанию для методов без меток.

Чтобы это работало, необходимо создать класс org.mockito.configuration.MockitoConfiguration ( обязательно в этом пакете ), который реализует интерфейс IMockitoConfiguration. Обычно удобно расширять класс DefaultMockitoConfiguration и переопределять только желаемое поведение.

01
02
03
04
05
06
07
08
09
10
11
package org.mockito.configuration;
 
import org.mockito.internal.stubbing.defaultanswers.ReturnsSmartNulls;
import org.mockito.stubbing.Answer;
 
public class MockitoConfiguration extends DefaultMockitoConfiguration {
 
    public Answer<Object> getDefaultAnswer() {
        return new ReturnsSmartNulls();
    }
}

После этой подготовки мы должны получить SmartNullPointerException с подробным выводом вместо чистого NullPointerException для каждого макета в нашем модуле.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
@Test(expectedExceptions = SmartNullPointerException.class)
public void shouldReturnNicerErrorMessageOnNPE() {
    //given
    //Mockito.RETURNS_SMART_NULLS not needed anymore
    WateringScheduler wateringSchedulerMock = mock(WateringScheduler.class);
    WaterSource waterSourceMock = mock(WaterSource.class);
    PlantWaterer plantWatererMock =
            new PlantWaterer(waterSourceMock, wateringSchedulerMock);
 
    //when
    plantWatererMock.generateNPE();
 
    //then
    //SmartNullPointerException exception expected
}

Этот пост является первой частью серии Beyond the Mockito refcard .

Ссылка: Помимо рефкарт Mockito — часть 1 — Лучшие сообщения об ошибках в NPE с глобально настроенным SmartNull от нашего партнера по JCG Марцина Заячковского в блоге Solid Soft .