Введение в PowerMock

Введение в PowerMock

1. обзор

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

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

Здесь вступает в игру фреймворкPowerMock.

PowerMockito - это API расширения PowerMock для поддержки Mockito. Он предоставляет возможности для работы с Java Reflection API простым способом преодоления проблем Mockito, таких как отсутствие способности имитировать конечные, статические или частные методы.

Из этого туториала вы узнаете, как использовать PowerMockito API и как его применять в тестах.

2. Подготовка к тестированию с PowerMockito

Первым шагом для интеграции поддержки PowerMock для Mockito является включение следующих двух зависимостей в файл POM Maven:


    org.powermock
    powermock-module-junit4
    1.6.4
    test


    org.powermock
    powermock-api-mockito
    1.6.4
    test

Затем нам нужно подготовить наши тестовые примеры для работы сPowerMockito, применив следующие две аннотации:

@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "com.example.powermockito.introduction.*")

ЭлементfullyQualifiedNames в аннотации@PrepareForTest представляет собой массив полностью определенных имен типов, которые мы хотим имитировать. В этом случае мы используем имя пакета с подстановочным знаком, чтобы указатьPowerMockito подготовить все типы в пакетеcom.example.powermockito.introduction для имитации.

Теперь мы готовы использовать силуPowerMockito.

3. Мокирующие конструкторы и финальные методы

В этом разделе мы продемонстрируем способы получить фиктивный экземпляр вместо реального при создании экземпляра класса с операторомnew, а затем использовать этот объект для имитации финального метода. Сотрудничающий класс, чьи конструкторы и конечные методы будут проверены, определяется следующим образом:

public class CollaboratorWithFinalMethods {
    public final String helloMethod() {
        return "Hello World!";
    }
}

Сначала мы создаем фиктивный объект с помощью APIPowerMockito:

CollaboratorWithFinalMethods mock = mock(CollaboratorWithFinalMethods.class);

Затем установите ожидание, говорящее, что всякий раз, когда вызывается конструктор no-arg этого класса, должен возвращаться фиктивный экземпляр, а не реальный:

whenNew(CollaboratorWithFinalMethods.class).withNoArguments().thenReturn(mock);

Давайте посмотрим, как этот макет конструкции работает в действии, создав экземпляр классаCollaboratorWithFinalMethods с помощью конструктора по умолчанию, а затем проверим поведение PowerMock:

CollaboratorWithFinalMethods collaborator = new CollaboratorWithFinalMethods();
verifyNew(CollaboratorWithFinalMethods.class).withNoArguments();

На следующем шаге ожидание устанавливается для окончательного метода:

when(collaborator.helloMethod()).thenReturn("Hello example!");

Этот метод затем выполняется:

String welcome = collaborator.helloMethod();

Следующие утверждения подтверждают, что методhelloMethod был вызван для объектаcollaborator и возвращает значение, установленное ложным ожиданием:

Mockito.verify(collaborator).helloMethod();
assertEquals("Hello example!", welcome);

Если мы хотим имитировать конкретный финальный метод, а не все финальные внутри объекта, может пригодиться методMockito.spy(T object). Это показано в разделе 5.

4. Насмешливые статические методы

Предположим, мы хотим имитировать статические методы класса с именемCollaboratorWithStaticMethods.. Этот класс объявлен следующим образом:

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!";
    }
}

Чтобы имитировать эти статические методы, нам нужно зарегистрировать включающий класс в APIPowerMockito:

mockStatic(CollaboratorWithStaticMethods.class);

В качестве альтернативы мы можем использовать методMockito.spy(Class<T> class), чтобы имитировать конкретный, как показано в следующем разделе.

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

when(CollaboratorWithStaticMethods.firstMethod(Mockito.anyString()))
  .thenReturn("Hello example!");
when(CollaboratorWithStaticMethods.secondMethod()).thenReturn("Nothing special");

Или может быть выбрано исключение при вызове методаthirdMethod:

doThrow(new RuntimeException()).when(CollaboratorWithStaticMethods.class);
CollaboratorWithStaticMethods.thirdMethod();

Теперь пришло время выполнить первые два метода:

String firstWelcome = CollaboratorWithStaticMethods.firstMethod("Whoever");
String secondWelcome = CollaboratorWithStaticMethods.firstMethod("Whatever");

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

assertEquals("Hello example!", firstWelcome);
assertEquals("Hello example!", secondWelcome);

Мы также можем проверить поведение имитационных методов, включая то, сколько раз метод вызывается. В этом случаеfirstMethod вызывается дважды, аsecondMethod никогда:

verifyStatic(Mockito.times(2));
CollaboratorWithStaticMethods.firstMethod(Mockito.anyString());

verifyStatic(Mockito.never());
CollaboratorWithStaticMethods.secondMethod();

Note: МетодverifyStatic должен вызываться непосредственно перед любой проверкой статического метода дляPowerMockito, чтобы знать, что последующий вызов метода - это то, что необходимо проверить.

Наконец, статический методthirdMethod должен выдаватьRuntimeException, как было объявлено ранее в макете. Это подтверждается элементомexpected аннотации@Test:

@Test(expected = RuntimeException.class)
public void givenStaticMethods_whenUsingPowerMockito_thenCorrect() {
    // other methods

    CollaboratorWithStaticMethods.thirdMethod();
}

5. Частичное издевательство

Вместо издевательства над всем классом APIPowerMockito позволяет имитировать его часть с помощью методаspy. Следующий класс будет использоваться в качестве коллаборатора для иллюстрации поддержки PowerMock для частичной имитации:

public class CollaboratorForPartialMocking {
    public static String staticMethod() {
        return "Hello example!";
    }

    public final String finalMethod() {
        return "Hello example!";
    }

    private String privateMethod() {
        return "Hello example!";
    }

    public String privateMethodCaller() {
        return privateMethod() + " Welcome to the Java world.";
    }
}

Начнем с имитации статического метода, который названstaticMethod в приведенном выше определении класса. Во-первых, используйте APIPowerMockito, чтобы частично смоделировать класс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);

Теперь пришло время перейти к финальным и приватным методам. Чтобы проиллюстрировать частичное высмеивание этих методов, нам нужно создать экземпляр класса и сообщить APIPowerMockitospy:

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();

Тест проверяет, что вызов методаfinalMethod вернет значение, соответствующее ожидаемому:

assertEquals("I am a final mock method.", returnValue);

Аналогичный процесс применяется к приватному методу. Основное отличие состоит в том, что мы не можем напрямую вызвать этот метод из тестового примера. По сути, закрытый метод должен вызываться другими из того же класса. В классеCollaboratorForPartialMocking методprivateMethod должен вызываться методомprivateMethodCaller, и мы будем использовать последний в качестве делегата. Начнем с ожидания и призыва:

when(mock, "privateMethod").thenReturn("I am a private mock method.");
returnValue = mock.privateMethodCaller();

Насмешка над приватным методом подтверждается:

verifyPrivate(mock).invoke("privateMethod");

Следующий тест проверяет, что возвращаемое значение от вызова частного метода совпадает с ожидаемым:

assertEquals("I am a private mock method. Welcome to the Java world.", returnValue);

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

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

Реализацию этих примеров и фрагментов кода можно найти вthe linked GitHub project.