Mockito e JUnit 5 - Usando ExtendWith
1. Introdução
Neste artigo rápido, mostraremoshow to integrate Mockito with the JUnit 5 extension model. Para saber mais sobre o modelo de extensão JUnit 5, dê uma olhada nestearticle.
Primeiro, mostraremos como criar uma extensão que cria automaticamente objetos fictícios para qualquer atributo de classe ou parâmetro de método anotado com@Mock.
Em seguida, usaremos nossa extensão Mockito em uma classe de teste JUnit 5.
2. Dependências do Maven
2.1. Dependências necessárias
Vamos adicionar as dependências JUnit 5 (júpiter) emockito ao nossopom.xml:
org.junit.jupiter
junit-jupiter-engine
5.3.1
test
org.mockito
mockito-core
2.21.0
test
Observe que junit-jupiter-engine é a biblioteca principal do JUnit 5 ejunit-platform-launcher é usado com o plugin Maven e o iniciador IDE.
2.2. Plugin Surefire
Vamos também configurar o plug-in Maven Surefire para executar nossas classes de teste usando o novo iniciador de plataforma JUnit:
maven-surefire-plugin
2.19.1
org.junit.platform
junit-platform-surefire-provider
1.0.1
2.3. Dependências de compatibilidade do JUnit 4 IDE
Para que nossos casos de teste sejam compatíveis com JUnit4 (vintage), para IDEs que ainda não têm suporte para JUnit 5, vamos incluir estas dependências:
org.junit.platform
junit-platform-runner
1.2.0
test
org.junit.vintage
junit-vintage-engine
5.2.0
test
Além disso, devemos considerar anotar todas as nossas classes de teste com@RunWith(JUnitPlatform.class)
As versões mais recentes dejunit-jupiter-engine,junit-vintage-engine,junit-platform-launcher emockito-core podem ser baixadas do Maven Central.
3. Extensão Mockito
Mockito fornece uma implementação para extensões JUnit5 na biblioteca -mockito-junit-jupiter. Incluiremos essa dependência em nossopom.xml:
org.mockito
mockito-junit-jupiter
2.23.0
test
4. Construindo a Classe de Teste
Vamos criar nossa classe de teste e anexar a extensão Mockito a ela:
@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class UserServiceUnitTest {
UserService userService;
... //
}
Podemos usar a anotação@Mock para injetar um mock para uma variável de instância que podemos usar em qualquer lugar na classe de teste:
@Mock UserRepository userRepository;
Além disso, podemos injetar objetos simulados nos parâmetros do método:
@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);
}
Observe o uso deMockito.lenient() aqui. Mockito lança umUnsupportedStubbingException, quando um mock inicializado não é chamado por um dos métodos de teste durante a execução. Podemos evitar essa verificação rigorosa de stub usando esse método ao inicializar as simulações.
Podemos até injetar um objeto simulado em um parâmetro do método de teste:
@Test
void givenValidUser_whenSaveUser_thenSucceed(@Mock MailClient mailClient) {
// Given
user = new User("Jerry", 12);
when(userRepository.insert(any(User.class))).then(new Answer() {
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);
}
Observe que o mockMailClient que injetamos como um parâmetro de teste NÃO será a mesma instância que injetamos no métodoinit.
5. Conclusão
O Junit 5 forneceu um bom modelo para extensão. Demonstramos uma extensão simples do Mockito que simplificou nossa lógica de criação simulada.
Todo o código usado neste artigo pode ser encontrado no pacotecom.example.junit5.mockito doGitHub project, junto com alguns métodos de teste de unidade adicionais.