Как использовать Mockito с JUnit5

108

Как я могу использовать инъекцию с Mockito и JUnit 5?

В JUnit4 я могу просто использовать @RunWith(MockitoJUnitRunner.class)аннотацию. В JUnit5 нет @RunWithаннотации?

Даниэль Кафер
источник

Ответы:

152

Есть разные способы использования Mockito - я рассмотрю их один за другим.

Вручную

Создание макетов вручную с помощью Mockito::mockработает независимо от версии JUnit (или тестовой среды в этом отношении).

На основе аннотации

Использование @Mock -annotation и соответствующий вызов MockitoAnnotations::initMocks для создания издевается работает независимо от версии JUnit (или тестовой базы по этому вопросу , но Java 9 может помешать здесь, в зависимости от того, заканчивается ли тестовый код в модуле или нет).

Расширение Mockito

JUnit 5 имеет мощную модель расширения, и Mockito недавно опубликовал ее под идентификатором группы / артефакта org.mockito : mockito-junit-jupiter .

Вы можете применить расширение, добавив @ExtendWith(MockitoExtension.class)его в тестовый класс и пометив имитируемые поля с помощью @Mock. Из MockitoExtensionJavaDoc:

@ExtendWith(MockitoExtension.class)
public class ExampleTest {

    @Mock
    private List list;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }

}

Документация MockitoExtension описывает другие способы создания экземпляров моков, например, с помощью внедрения конструктора (если вы rpefer конечные поля в тестовых классах).

Нет правил, нет бегунов

Правила и бегуны JUnit 4 не работают в JUnit 5, поэтому бегункиMockitoRule и Mockito использовать нельзя.

Николай Парлог
источник
6
Теперь существует официальное расширение Mockito Junit5, которое эквивалентно MockitoJUnitRunner -> mockito-junit-jupiter
dan carter
Когда было выпущено официальное расширение для Mockito, он написал сообщение в блоге с более подробной информацией о том, как его настроить и использовать: solidsoft.wordpress.com/2018/03/27/…
Марцин Зайончковски
Должен ли аннотированный метод @Testбыть общедоступным или достаточно "закрытым"?
Компьютерщик,
При запуске тестов с Jupiter (часто называемым «JUnit 5») методы тестирования должны быть доступны только для пакетов.
Николай Парлог,
60

Используйте Mockito's MockitoExtension. Расширение содержится в новом артефакте mockito-junit-jupiter:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>2.23.4</version>
    <scope>test</scope>
</dependency>

Это позволяет вам писать тесты, как в JUnit 4:

import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;

@ExtendWith(MockitoExtension.class)
class MyTest {

    @Mock
    private Foo foo;

    @InjectMocks
    private Bar bar; // constructor injection

    ...
}
Джонатан
источник
7
@ExtendWith(MockitoExtension.class)эквивалент @RunWith(MockitoJUnitRunner.class)JUnit4
Сергей Немчинов
Могу ли я выполнить несколько вызовов метода с разными возвращаемыми значениями для метода объекта Mock с использованием MockitoExtension.class в JUnit5
Радж Хассани,
@RajHassani Да, вы можете, смотрите здесь .
Джонатан
10

Есть разные способы сделать, но более чистый способ, который также уважает философию JUnit 5, - это создание org.junit.jupiter.api.extension.Extensionдля Mockito.

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

2) Вызов MockitoAnnotations.initMocks(this)каждого тестового класса - это шаблонный код, которого мы могли бы избежать.
И создание такой настройки в абстрактном классе тоже не лучшее решение.
Он связывает все тестовые классы с базовым классом.
Если по уважительным причинам вам потребуется новый базовый тестовый класс, вы закончите с трехуровневой иерархией классов. Пожалуйста, избегайте этого.

3) Правила тестирования - это специфика JUnit 4.
Даже не думай об этом.
И в документации об этом ясно сказано:

Однако, если вы намереваетесь разработать новое расширение для JUnit 5, используйте новую модель расширения JUnit Jupiter вместо модели JUnit 4 на основе правил.

4) Test Runner на самом деле не способ расширения JUnit 5 framework.
JUnit 5 упростил аду исполнителей JUnit 4, предоставив модель расширения для написания тестов благодаря JUnit 5 Extensions.
Даже не думай об этом.

Так что пользуйтесь org.junit.jupiter.api.extension.Extensionдорогой.


РЕДАКТИРОВАТЬ: На самом деле Mockito связывает расширение jupiter: mockito-junit-jupiter

Тогда очень просто использовать:

import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class FooTest {
     ...    
}

Вот дополнение к отличному ответу Джонатана.

Путем добавления mockito-junit-jupiterартефакта в качестве зависимости использование @ExtendWith(MockitoExtension.class)привело к следующему исключению при выполнении теста:

java.lang.NoSuchMethodError: org.junit.platform.commons.support.AnnotationSupport.findAnnotation (Ljava / util / Необязательно; Ljava / lang / Class;) Ljava / util / Необязательно;

Проблема в том, что это mockito-junit-jupiterзависит от двух независимых библиотек. Например для mockito-junit-jupiter:2.19.0:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>2.19.0</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-api</artifactId>
  <version>5.1.0</version>
  <scope>runtime</scope>
</dependency>

Проблема была в том, что я использовал junit-jupiter-api:5.0.1.

Так , как junit-jupiter-apiдвижется по- прежнему часто с точки зрения API, убедитесь , что вы зависите от одной и той же версии , junit-jupiter-apiчто mockito-junit-jupiterзависит от.

davidxxx
источник
почему не mockito-junit-jupiterтянет нужную версию junit-jupiter-api?
haelix
@haelix Потому что стратегия версий, используемая для этой зависимости, основана на библиотеке Mockito. Посмотрите версию здесь mockito-junit-jupiter:2.19.0. Хотя версии JUnit Jupiter начинаются с 5. mockito-junit-jupiter должен был указать в своем идентификаторе артефакта две вещи (версию Mockito и версию JUnit Jupiter), чтобы было понятнее. Например, mockito-junit-jupiter-5.1:2.19.0чтобы передать, что библиотека разработана для JUnit Jupiter 5.1.
davidxxx
MockitoExtensionне существует в mockito-coreверсии 3.0.0.
Thunderforge
1
@Thunderforge Это определено вmockito-junit-jupiter
davidxxx
3

Вы должны использовать новую @ExtendWithаннотацию.

К сожалению, расширения еще нет. На github вы можете увидеть бета-версию расширения. в качестве примера демонстрационного теста .

Даниэль Кафер
источник