JUnit5 with Mockito using @ExtendWith (#2770)
* JUnit5 with Mockito using @ExtendWith * rename method: givenUserWithExistingName_whenSaveUser_thenGiveUsernameAlreadyExistsError rename this class according to the standard -- UserServiceUnitTest.java
This commit is contained in:
parent
fb283f35c7
commit
26f38c1b69
|
@ -19,11 +19,12 @@
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<junit.jupiter.version>5.0.0-RC2</junit.jupiter.version>
|
<junit.jupiter.version>5.0.1</junit.jupiter.version>
|
||||||
<junit.platform.version>1.0.0-RC2</junit.platform.version>
|
<junit.platform.version>1.0.1</junit.platform.version>
|
||||||
<junit.vintage.version>4.12.0-RC2</junit.vintage.version>
|
<junit.vintage.version>4.12.1</junit.vintage.version>
|
||||||
<log4j2.version>2.8.2</log4j2.version>
|
<log4j2.version>2.8.2</log4j2.version>
|
||||||
<h2.version>1.4.196</h2.version>
|
<h2.version>1.4.196</h2.version>
|
||||||
|
<mockito.version>2.11.0</mockito.version>
|
||||||
|
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.baeldung.junit5.mockito;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String name, int age) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.baeldung.junit5.mockito.repository;
|
||||||
|
|
||||||
|
import com.baeldung.junit5.mockito.User;
|
||||||
|
|
||||||
|
public interface MailClient {
|
||||||
|
|
||||||
|
void sendUserRegistrationMail(User user);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.baeldung.junit5.mockito.repository;
|
||||||
|
|
||||||
|
public interface SettingRepository {
|
||||||
|
|
||||||
|
int getUserMinAge();
|
||||||
|
|
||||||
|
int getUserNameMinLength();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.baeldung.junit5.mockito.repository;
|
||||||
|
|
||||||
|
import com.baeldung.junit5.mockito.User;
|
||||||
|
|
||||||
|
public interface UserRepository {
|
||||||
|
|
||||||
|
User insert(User user);
|
||||||
|
boolean isUsernameAlreadyExists(String userName);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.baeldung.junit5.mockito.service;
|
||||||
|
|
||||||
|
import com.baeldung.junit5.mockito.User;
|
||||||
|
import com.baeldung.junit5.mockito.repository.MailClient;
|
||||||
|
import com.baeldung.junit5.mockito.repository.SettingRepository;
|
||||||
|
import com.baeldung.junit5.mockito.repository.UserRepository;
|
||||||
|
|
||||||
|
public class DefaultUserService implements UserService {
|
||||||
|
|
||||||
|
private UserRepository userRepository;
|
||||||
|
private SettingRepository settingRepository;
|
||||||
|
private MailClient mailClient;
|
||||||
|
|
||||||
|
public DefaultUserService(UserRepository userRepository, SettingRepository settingRepository, MailClient mailClient) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.settingRepository = settingRepository;
|
||||||
|
this.mailClient = mailClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User register(User user) {
|
||||||
|
validate(user);
|
||||||
|
User insertedUser = userRepository.insert(user);
|
||||||
|
mailClient.sendUserRegistrationMail(insertedUser);
|
||||||
|
return insertedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate(User user) {
|
||||||
|
if(user.getName() == null) {
|
||||||
|
throw new RuntimeException(Errors.USER_NAME_REQUIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(user.getName().length() < settingRepository.getUserNameMinLength()) {
|
||||||
|
throw new RuntimeException(Errors.USER_NAME_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(user.getAge() < settingRepository.getUserMinAge()) {
|
||||||
|
throw new RuntimeException(Errors.USER_AGE_YOUNG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(userRepository.isUsernameAlreadyExists(user.getName())) {
|
||||||
|
throw new RuntimeException(Errors.USER_NAME_DUPLICATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.baeldung.junit5.mockito.service;
|
||||||
|
|
||||||
|
public class Errors {
|
||||||
|
|
||||||
|
public static final String USER_NAME_REQUIRED = "user.name.required";
|
||||||
|
public static final String USER_NAME_SHORT = "user.name.short";
|
||||||
|
public static final String USER_AGE_YOUNG = "user.age.young";
|
||||||
|
public static final String USER_NAME_DUPLICATE = "user.name.duplicate";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.baeldung.junit5.mockito.service;
|
||||||
|
|
||||||
|
import com.baeldung.junit5.mockito.User;
|
||||||
|
|
||||||
|
public interface UserService {
|
||||||
|
|
||||||
|
User register(User user);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015-2016 the original author or authors.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials are
|
||||||
|
* made available under the terms of the Eclipse Public License v1.0 which
|
||||||
|
* accompanies this distribution and is available at
|
||||||
|
*
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.baeldung.junit5.mockito;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||||
|
import org.junit.jupiter.api.extension.ParameterContext;
|
||||||
|
import org.junit.jupiter.api.extension.ParameterResolver;
|
||||||
|
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code MockitoExtension} showcases the {@link TestInstancePostProcessor}
|
||||||
|
* and {@link ParameterResolver} extension APIs of JUnit 5 by providing
|
||||||
|
* dependency injection support at the field level and at the method parameter
|
||||||
|
* level via Mockito 2.x's {@link Mock @Mock} annotation.
|
||||||
|
*
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public class MockitoExtension implements TestInstancePostProcessor, ParameterResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcessTestInstance(Object testInstance, ExtensionContext context) {
|
||||||
|
MockitoAnnotations.initMocks(testInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
|
||||||
|
return parameterContext.getParameter().isAnnotationPresent(Mock.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
|
||||||
|
return getMock(parameterContext.getParameter(), extensionContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getMock(Parameter parameter, ExtensionContext extensionContext) {
|
||||||
|
Class<?> mockType = parameter.getType();
|
||||||
|
Store mocks = extensionContext.getStore(Namespace.create(MockitoExtension.class, mockType));
|
||||||
|
String mockName = getMockName(parameter);
|
||||||
|
|
||||||
|
if (mockName != null) {
|
||||||
|
return mocks.getOrComputeIfAbsent(mockName, key -> mock(mockType, mockName));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return mocks.getOrComputeIfAbsent(mockType.getCanonicalName(), key -> mock(mockType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMockName(Parameter parameter) {
|
||||||
|
String explicitMockName = parameter.getAnnotation(Mock.class).name().trim();
|
||||||
|
if (!explicitMockName.isEmpty()) {
|
||||||
|
return explicitMockName;
|
||||||
|
}
|
||||||
|
else if (parameter.isNamePresent()) {
|
||||||
|
return parameter.getName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.baeldung.junit5.mockito;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.platform.runner.JUnitPlatform;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import com.baeldung.junit5.mockito.repository.MailClient;
|
||||||
|
import com.baeldung.junit5.mockito.repository.SettingRepository;
|
||||||
|
import com.baeldung.junit5.mockito.repository.UserRepository;
|
||||||
|
import com.baeldung.junit5.mockito.service.DefaultUserService;
|
||||||
|
import com.baeldung.junit5.mockito.service.Errors;
|
||||||
|
import com.baeldung.junit5.mockito.service.UserService;
|
||||||
|
|
||||||
|
@RunWith(JUnitPlatform.class)
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class UserServiceUnitTest {
|
||||||
|
|
||||||
|
UserService userService;
|
||||||
|
@Mock UserRepository userRepository;
|
||||||
|
|
||||||
|
User user;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void init(@Mock SettingRepository settingRepository, @Mock MailClient mailClient) {
|
||||||
|
userService = new DefaultUserService(userRepository, settingRepository, mailClient);
|
||||||
|
when(settingRepository.getUserMinAge()).thenReturn(10);
|
||||||
|
when(settingRepository.getUserNameMinLength()).thenReturn(4);
|
||||||
|
when(userRepository.isUsernameAlreadyExists(any(String.class))).thenReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// When
|
||||||
|
User insertedUser = userService.register(user);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
verify(userRepository).insert(user);
|
||||||
|
Assertions.assertNotNull(user.getId());
|
||||||
|
verify(mailClient).sendUserRegistrationMail(insertedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenShortName_whenSaveUser_thenGiveShortUsernameError() {
|
||||||
|
// Given
|
||||||
|
user = new User("tom", 12);
|
||||||
|
|
||||||
|
// When
|
||||||
|
try {
|
||||||
|
userService.register(user);
|
||||||
|
fail("Should give an error");
|
||||||
|
} catch(Exception ex) {
|
||||||
|
assertEquals(ex.getMessage(), Errors.USER_NAME_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then
|
||||||
|
verify(userRepository, never()).insert(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenSmallAge_whenSaveUser_thenGiveYoungUserError() {
|
||||||
|
// Given
|
||||||
|
user = new User("jerry", 3);
|
||||||
|
|
||||||
|
// When
|
||||||
|
try {
|
||||||
|
userService.register(user);
|
||||||
|
fail("Should give an error");
|
||||||
|
} catch(Exception ex) {
|
||||||
|
assertEquals(ex.getMessage(), Errors.USER_AGE_YOUNG);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then
|
||||||
|
verify(userRepository, never()).insert(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUserWithExistingName_whenSaveUser_thenGiveUsernameAlreadyExistsError() {
|
||||||
|
// Given
|
||||||
|
user = new User("jerry", 12);
|
||||||
|
Mockito.reset(userRepository);
|
||||||
|
when(userRepository.isUsernameAlreadyExists(any(String.class))).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
try {
|
||||||
|
userService.register(user);
|
||||||
|
fail("Should give an error");
|
||||||
|
} catch(Exception ex) {
|
||||||
|
assertEquals(ex.getMessage(), Errors.USER_NAME_DUPLICATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then
|
||||||
|
verify(userRepository, never()).insert(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue