«1. Обзор

Одной из проблем модульного тестирования является имитация закрытых методов.

В этом руководстве мы узнаем, как этого добиться с помощью библиотеки PowerMock, которая поддерживается JUnit и TestNG.

PowerMock интегрируется с такими фреймворками для имитации, как EasyMock и Mockito, и предназначен для добавления к ним дополнительных функций, таких как имитация закрытых методов, конечных классов, конечных методов и т. д.

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

2. Зависимости Maven

Во-первых, давайте добавим необходимые зависимости для использования PowerMock с Mockito и JUnit в наш pom.xml:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.7.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>1.7.3</version>
    <scope>test</scope>
</dependency>

Последние версии можно проверить здесь и здесь.

3. Пример

Давайте начнем с примера LuckyNumberGenerator. Этот класс имеет единственный общедоступный метод для генерации счастливого числа:

public int getLuckyNumber(String name) {
    saveIntoDatabase(name);
    if (name == null) {
        return getDefaultLuckyNumber();
    }
    return getComputedLuckyNumber(name.length());
}

4. Вариации имитации приватных методов

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

4.1. Метод без аргументов, но с возвращаемым значением

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

LuckyNumberGenerator mock = spy(new LuckyNumberGenerator());

when(mock, "getDefaultLuckyNumber").thenReturn(300);

В этом случае мы имитируем приватный метод getDefaultLuckyNumber и заставить его возвращать значение 300.

4.2. Метод с аргументом и возвращаемым значением

Далее давайте сымитируем поведение частного метода с аргументом и заставим его возвращать желаемое значение:

LuckyNumberGenerator mock = spy(new LuckyNumberGenerator());

doReturn(1).when(mock, "getComputedLuckyNumber", ArgumentMatchers.anyInt());

В этом случае мы смоделируем частный метод и заставим его возвращать значение 1.

Обратите внимание, что мы не заботимся о входном аргументе и используем ArgumentMatchers.anyInt() в качестве подстановочного знака.

4.3. Проверка вызова метода

Наша последняя стратегия заключается в использовании PowerMock для проверки вызова закрытого метода:

LuckyNumberGenerator mock = spy(new LuckyNumberGenerator());
int result = mock.getLuckyNumber("Tyranosorous");

verifyPrivate(mock).invoke("saveIntoDatabase", ArgumentMatchers.anyString());

5. Предостережение

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

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

Методы имитации следует применять к внешним зависимостям класса, а не к самому классу.

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

6. Заключение

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

Исходный код этого руководства можно найти на GitHub.