Перейти к основному содержимому

Mockito и JUnit 5 — Использование ExtendWith

· 3 мин. чтения

1. Обзор

В этом кратком руководстве мы покажем, как интегрировать Mockito с моделью расширения JUnit 5. Чтобы узнать больше о модели расширения JUnit 5, ознакомьтесь с этой статьей .

Сначала мы покажем, как создать расширение, которое автоматически создает фиктивные объекты для любого атрибута класса или параметра метода, аннотированного @Mock .

Затем мы будем использовать наше расширение Mockito в тестовом классе JUnit 5.

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

2.1. Требуемые зависимости

Давайте добавим зависимости JUnit 5 (jupiter) и mockito в наш pom.xml :

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.0</version>
<scope>test</scope>
</dependency>

Обратите внимание, что junit-jupiter-engine — это основная библиотека JUnit 5, а junit-platform-launcher используется с подключаемым модулем Maven и средством запуска IDE.

2.2. Плагин Surefire

Давайте также настроим подключаемый модуль Maven Surefire для запуска наших тестовых классов с помощью новой панели запуска платформы JUnit:

<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>
</plugin>

2.3. Зависимости совместимости JUnit 4 IDE

Чтобы наши тестовые примеры были совместимы с JUnit4 (vintage), для IDE, которые еще не поддерживают JUnit 5, давайте включим эти зависимости:

<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>

Кроме того, мы должны рассмотреть возможность аннотирования всех наших тестовых классов с помощью @RunWith(JUnitPlatform.class) .

Последние версии junit-jupiter-engine , junit-vintage-engine , junit-platform-launcher и mockito-core можно загрузить с Maven Central.

3. Расширение Мокито

Mockito предоставляет реализацию расширений JUnit5 в библиотеке — mockito-junit-jupiter .

Мы включим эту зависимость в наш pom.xml :

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

4. Создание тестового класса

Давайте создадим наш тестовый класс и присоединим к нему расширение Mockito:

@ExtendWith(MockitoExtension.class)
public class UserServiceUnitTest {

UserService userService;

... //
}

Мы можем использовать аннотацию @Mock , чтобы внедрить макет для переменной экземпляра, которую мы можем использовать в любом месте тестового класса:

@Mock UserRepository userRepository;

Кроме того, мы можем внедрить фиктивные объекты в параметры метода:

@BeforeEach
void init(@Mock SettingRepository settingRepository) {
userService = new DefaultUserService(userRepository, settingRepository, mailClient);

Mockito.lenient().when(settingRepository.getUserMinAge()).thenReturn(10);

when(settingRepository.getUserNameMinLength()).thenReturn(4);

Mockito.lenient()
.when(userRepository.isUsernameAlreadyExists(any(String.class)))
.thenReturn(false);
}

Обратите внимание на использование Mockito.lenient() здесь. Mockito генерирует исключение UnsupportedStubbingException , когда инициализированный макет не вызывается одним из тестовых методов во время выполнения. Мы можем избежать этой строгой проверки заглушек, используя этот метод при инициализации макетов.

Мы даже можем внедрить фиктивный объект в параметр тестового метода:

@Test
void givenValidUser_whenSaveUser_thenSucceed(@Mock MailClient mailClient) {
// Given
user = new User("Jerry", 12);
when(userRepository.insert(any(User.class))).then(new Answer<User>() {
int sequence = 1;

@Override
public User answer(InvocationOnMock invocation) throws Throwable {
User user = (User) invocation.getArgument(0);
user.setId(sequence++);
return user;
}
});

userService = new DefaultUserService(userRepository, settingRepository, mailClient);

// When
User insertedUser = userService.register(user);

// Then
verify(userRepository).insert(user);
Assertions.assertNotNull(user.getId());
verify(mailClient).sendUserRegistrationMail(insertedUser);
}

Обратите внимание, что макет MailClient , который мы вводим в качестве тестового параметра, НЕ будет тем же экземпляром, который мы ввели в методе init .

5. Вывод

Junit 5 предоставил хорошую модель для расширения. Мы продемонстрировали простое расширение Mockito, которое упростило логику создания макета.

Весь код, использованный в этой статье, можно найти в пакете com.foreach.junit5.mockito проекта GitHub вместе с несколькими дополнительными методами модульного тестирования.