«1. Обзор
Модульное тестирование с помощью мок-фреймворка уже давно признано полезной практикой, а фреймворк Mockito, в частности, доминировал на этом рынке в последние годы.
А для того, чтобы упростить дизайн кода и сделать общедоступный API простым, некоторые желаемые функции были намеренно опущены. Однако в некоторых случаях эти недостатки вынуждают тестировщиков писать громоздкий код только для того, чтобы сделать возможным создание макетов.
Здесь в игру вступает инфраструктура PowerMock.
PowerMockito — это API расширения PowerMock для поддержки Mockito. Он предоставляет возможности для работы с Java Reflection API простым способом для преодоления проблем Mockito, таких как отсутствие возможности имитировать окончательные, статические или частные методы.
Этот туториал познакомит вас с PowerMockito API и его применением в тестах.
2. Подготовка к тестированию с помощью PowerMockito
Первым шагом для интеграции поддержки PowerMock для Mockito является включение следующих двух зависимостей в файл Maven POM:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
Далее нам нужно подготовить наши тестовые примеры. для работы с PowerMockito, применяя следующие две аннотации:
@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "com.baeldung.powermockito.introduction.*")
Элемент fullQualifiedNames в аннотации @PrepareForTest представляет собой массив полных имен типов, которые мы хотим имитировать. В этом случае мы используем имя пакета с подстановочным знаком, чтобы указать PowerMockito подготовить все типы в пакете com.baeldung.powermockito.introduction для имитации.
Теперь мы готовы использовать мощь PowerMockito.
3. Мок-конструкторы и финальные методы
В этом разделе мы продемонстрируем способы получения фиктивного экземпляра вместо реального при создании экземпляра класса с оператором new, а затем используем этот объект для имитации финального метод. Сотрудничающий класс, чьи конструкторы и конечные методы будут имитироваться, определяется следующим образом:
public class CollaboratorWithFinalMethods {
public final String helloMethod() {
return "Hello World!";
}
}
Сначала мы создаем фиктивный объект, используя API PowerMockito:
CollaboratorWithFinalMethods mock = mock(CollaboratorWithFinalMethods.class);
Затем устанавливаем ожидание, говорящее, что всякий раз, когда вызывается конструктор без аргументов этого класса, должен быть возвращен фиктивный экземпляр, а не настоящий:
whenNew(CollaboratorWithFinalMethods.class).withNoArguments().thenReturn(mock);
Давайте посмотрим, как эта имитация конструкции работает в действии, создав экземпляр класса CollaboratorWithFinalMethods с помощью его конструктора по умолчанию, а затем проверить поведение PowerMock:
CollaboratorWithFinalMethods collaborator = new CollaboratorWithFinalMethods();
verifyNew(CollaboratorWithFinalMethods.class).withNoArguments();
На следующем шаге ожидание устанавливается для конечного метода:
when(collaborator.helloMethod()).thenReturn("Hello Baeldung!");
Затем выполняется этот метод:
String welcome = collaborator.helloMethod();
Следующие утверждения подтверждают, что Метод helloMethod был вызван для объекта-сотрудника и возвращает значение, установленное ложным ожиданием: T object) может пригодиться. Это показано в разделе 5.
Mockito.verify(collaborator).helloMethod();
assertEquals("Hello Baeldung!", welcome);
4. Имитация статических методов
Предположим, мы хотим имитировать статические методы класса CollaboratorWithStaticMethods. Этот класс объявлен следующим образом:
Чтобы имитировать эти статические методы, нам нужно зарегистрировать включающий класс в PowerMockito API:
public class CollaboratorWithStaticMethods {
public static String firstMethod(String name) {
return "Hello " + name + " !";
}
public static String secondMethod() {
return "Hello no one!";
}
public static String thirdMethod() {
return "Hello no one again!";
}
}
В качестве альтернативы мы можем использовать Mockito.spy(Class \u003cT\u003e class) для имитации конкретного, как показано в следующем разделе.
mockStatic(CollaboratorWithStaticMethods.class);
Затем можно задать ожидания для определения значений, которые методы должны возвращать при вызове:
Или можно задать исключение, которое будет вызываться при вызове метода ThirdMethod:
when(CollaboratorWithStaticMethods.firstMethod(Mockito.anyString()))
.thenReturn("Hello Baeldung!");
when(CollaboratorWithStaticMethods.secondMethod()).thenReturn("Nothing special");
Теперь это время выполнения первых двух методов:
doThrow(new RuntimeException()).when(CollaboratorWithStaticMethods.class);
CollaboratorWithStaticMethods.thirdMethod();
Вместо вызова членов реального класса указанные выше вызовы делегируются методам макета. Следующие утверждения доказывают, что фиктивный объект вступил в силу:
String firstWelcome = CollaboratorWithStaticMethods.firstMethod("Whoever");
String secondWelcome = CollaboratorWithStaticMethods.firstMethod("Whatever");
Мы также можем проверить поведение методов фиктивного объекта, включая количество вызовов метода. В этом случае первый метод вызывался дважды, а второй — никогда:
assertEquals("Hello Baeldung!", firstWelcome);
assertEquals("Hello Baeldung!", secondWelcome);
«
verifyStatic(Mockito.times(2));
CollaboratorWithStaticMethods.firstMethod(Mockito.anyString());
verifyStatic(Mockito.never());
CollaboratorWithStaticMethods.secondMethod();
«Примечание. Метод verifyStatic должен вызываться непосредственно перед любой проверкой статического метода, чтобы PowerMockito знал, что последовательный вызов метода — это то, что необходимо проверить.
Наконец, статический метод ThirdMethod должен генерировать исключение RuntimeException, как было объявлено в макете ранее. Это подтверждается ожидаемым элементом аннотации @Test:
@Test(expected = RuntimeException.class)
public void givenStaticMethods_whenUsingPowerMockito_thenCorrect() {
// other methods
CollaboratorWithStaticMethods.thirdMethod();
}
5. Частичная имитация
Вместо того, чтобы имитировать весь класс, API PowerMockito позволяет имитировать его часть, используя шпионский метод. Следующий класс будет использоваться в качестве соавтора, чтобы проиллюстрировать поддержку PowerMock для частичного имитации:
public class CollaboratorForPartialMocking {
public static String staticMethod() {
return "Hello Baeldung!";
}
public final String finalMethod() {
return "Hello Baeldung!";
}
private String privateMethod() {
return "Hello Baeldung!";
}
public String privateMethodCaller() {
return privateMethod() + " Welcome to the Java world.";
}
}
Давайте начнем с имитации статического метода, который назван staticMethod в приведенном выше определении класса. Во-первых, используйте API PowerMockito, чтобы частично имитировать класс CollaboratorForPartialMocking и установить ожидание для его статического метода:
spy(CollaboratorForPartialMocking.class);
when(CollaboratorForPartialMocking.staticMethod()).thenReturn("I am a static mock method.");
Затем выполняется статический метод:
returnValue = CollaboratorForPartialMocking.staticMethod();
Поведение имитации проверяется следующим образом: ~~ ~
verifyStatic();
CollaboratorForPartialMocking.staticMethod();
Следующее утверждение подтверждает, что фиктивный метод действительно был вызван, сравнивая возвращаемое значение с ожидаемым:
assertEquals("I am a static mock method.", returnValue);
Теперь пришло время перейти к финальным и закрытым методам. Для того, чтобы проиллюстрировать частичное имитация этих методов, нам нужно создать экземпляр класса и указать API PowerMockito следить за ним:
CollaboratorForPartialMocking collaborator = new CollaboratorForPartialMocking();
CollaboratorForPartialMocking mock = spy(collaborator);
Объекты, созданные выше, используются для демонстрации имитации как конечных, так и закрытых методов. Теперь мы займемся окончательным методом, установив ожидание и вызвав метод:
when(mock.finalMethod()).thenReturn("I am a final mock method.");
returnValue = mock.finalMethod();
Доказано поведение частичного имитации этого метода: значение, соответствующее ожиданиям:
Mockito.verify(mock).finalMethod();
Аналогичный процесс применяется к частному методу. Основное отличие состоит в том, что мы не можем напрямую вызвать этот метод из тестового примера. По сути, частный метод должен вызываться другими из того же класса. В классе CollaboratorForPartialMocking метод privateMethod должен вызываться методом privateMethodCaller, и мы будем использовать последний в качестве делегата. Начнем с ожидания и вызова:
assertEquals("I am a final mock method.", returnValue);
Насмешка над закрытым методом подтверждена:
when(mock, "privateMethod").thenReturn("I am a private mock method.");
returnValue = mock.privateMethodCaller();
Следующий тест гарантирует, что возвращаемое значение при вызове закрытого метода такое же, как и ожидание :
verifyPrivate(mock).invoke("privateMethod");
6. Заключение
assertEquals("I am a private mock method. Welcome to the Java world.", returnValue);
В этом руководстве представлено введение в API PowerMockito, демонстрирующее его использование для решения некоторых проблем, с которыми сталкиваются разработчики при использовании платформы Mockito.
Реализацию этих примеров и фрагментов кода можно найти в связанном проекте GitHub.
«