Например, у меня в UserService есть такой метод:
@Override
@Transactional
public UserDto create(UserDto userDto) {
User dbUser = userRepository.findOne(userDto.getId());
if (dbUser != null) {
throw new AuthException(AuthException.ErrorCode.DUPLICATE_USER_EXCEPTION);
}
User oneByLogin = userRepository.findOneByLogin(userDto.getLogin());
if (oneByLogin != null) {
throw new AuthExceptionAuthException.ErrorCode.DUPLICATE_LOGIN_EXCEPTION);
}
User newUser = new User();
newUser.setGuid(UUID.randomUUID().toString());
newUser.setInsertDate(new Date());
newUser.setFirstName(userDto.getFirstName());
newUser.setLastName(userDto.getLastName());
newUser.setLogin(userDto.getLogin());
newUser.setPassword(userDto.getPassword());
newUser.setAuthToken(TokenGenerator.nextToken());
newUser.setAuthTokenCreatedDate(new Date());
User savedUser = userRepository.save(newUser);
userDto.setAuthToken(savedUser.getAuthToken());
log.info("User {0} created", savedUser.getLogin());
return userDto;
}
Как я могу создать модульный тест для этого метода? Я попробовал следующее:
@Test
public void createUser() {
UserDto userDtoRequest = new UserDto();
userDtoRequest.setLogin("Alex");
userDtoRequest.setPassword("123");
UserDto found = userService.create(userDtoRequest);
assertThat(found.getAuthToken()).isNotEmpty();
}
У меня следующая логика:
User dbUser = userRepository.findOne(userDto.getId()); dbUser = NULLif (dbUser != null) и if (oneByLogin != null) пропускаютUser savedUser = userRepository.save(newUser); savedUser = NULLНа этом этапе у меня проблема, потому что я не могу имитировать userRepository.save(newUser).
newUser create inside the method. and test fail.
saveUser.getAuthToken () - savedUser == NULL
Я могу переписать:
userRepository.save(newUser);
userDto.setAuthToken(newUser.getAuthToken());
log.info("User {0} created", newUser.getLogin());
return userDto;
но что, если я хочу использовать возвращенный объект savedUser?
@ grape_mao и как мне это сделать? как мне вызвать метод userRepository.save (newUser), если объект newUser создает внутри служебного метода, а у меня его нет в моем тесте. когда (userService.save (???)). thenReturn (???);
Если вы не можете написать тест для своего метода, это признак того, что вам нужно разделить его на несколько частей и протестировать их по отдельности.
@ ip696 у вас есть два варианта. 1. проигнорируйте переданный аргумент, верните User с токеном. 2. Используйте что-то вроде doAnswer для имитации метода, чтобы вы могли уловить аргумент.
Возможный дубликат Невозможно издеваться над репозиториями Spring-Data-JPA с помощью Mockito




Вы можете сделать следующее:
@RunWith(MockitoJUnitRunner.class)
public class SimpleTest {
@Mock
private UserRepository mockedUserRepository;
// .. your test setup
@Test
public void testYourMethod() {
User userToReturnFromRepository = new User();
userToReturnFromRepository.setAuthToken(YOUR_TOKEN);
when(mockedUserRepository.save(any(User.class)).thenReturn(userToReturnFromRepository);
UserDto found = userService.create(userDtoRequest);
// ... your asserts
}
}
при таком подходе вам просто нужно убедиться, что ваш mockedUserRepository внедрен в тестируемый класс (например, в конструктор).
Это рассматривает преобразование Entity в DTO внутри службы? repo 'save возвращает объект НЕ DTO, сервис должен его перевести
Вам нужно написать несколько тестовых случаев, чтобы протестировать разные сценарии.
Сценарий 1: когда findOne возвращает ненулевой объект:
@Test(expected=AuthException.class)
public void testCreateUserWhenAvailable() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(new User());
userService.create(userDto);
}
Сценарий 2: когда findOneByLogin возвращает нулевой объект:
@Test(expected=AuthException.class)
public void testCreateUserWhenLoginAvailable() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(new User());
userService.create(userDto);
}
Сценарий 2: когда выполнено спасти:
@Контрольная работа
public void testCreateUserWhenSaved() {
//Create one sample userDto object with test data
when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(null);
//Create sample User object and set all the properties
User newUser=new User();
when(mockedUserRepository.save(Mockito.any(User.class)).thenReturn(newUser);
User returnedUser=userService.create(userDto);
//You have two ways to test, you can either verify that save method was invoked by
//verify method
verify(mockedUserRepository, times(1)).save(Mockito.any(User.class);
//or by assertion statements, match the authToken in the returned object to be equal
//to the one set by you in the mocked object
Assert.assertEquals(returnedUser.getAuthToken(),newUser.getAuthToken());
}
Наиболее полный ответ здесь.
Вам нужно это сделать.
when(userRepository.save(Mockito.any(User.class)))
.thenAnswer(i -> i.getArguments()[0]);
И теперь вы можете получить пользователя, которого передаете в качестве аргумента.
та же процедура, но с более читаемой функцией returnFirstArg () может быть найдена здесь stackoverflow.com/questions/2684630/…
Всего два цента от меня о том, как создать метод save репозитория JPA с генерацией случайных идентификаторов для полей с помощью @GeneratedValue.
/**
* Mocks {@link JpaRepository#save(Object)} method to return the
* saved entity as it was passed as parameter and add generated ID to it.
* If ID could not be generated, it will be ignored.
* If parameter already has and ID, it will be overridden.
*/
private <T, V> void mockSave(JpaRepository<T, V> repository) {
when(repository.save(any())).thenAnswer(i -> {
Object argument = i.getArgument(0);
Arrays.stream(argument.getClass().getDeclaredFields())
.filter(f -> f.getAnnotation(GeneratedValue.class) != null)
.forEach(f -> enrichGeneratedValueField(argument, f));
return argument;
});
}
Итак, здесь вы передаете желаемый репозиторий в качестве параметра, и методы вызывают enrichGeneratedValueField для всех полей, аннотированных аннотацией @GeneratedValue. Вот реализация этого метода:
private void enrichGeneratedValueField(Object argument, Field field) {
try {
if (field.getType().isAssignableFrom(Integer.class)) {
FieldUtils.writeField(field, argument, Math.abs(random.nextInt()), true);
} else {
FieldUtils.writeField(field, argument, mock(field.getType()), true);
}
} catch (Exception ignored) {
}
}
В этом примере я использовал только идентификаторы типа Integer, но заполните их, чтобы добавить желаемый тип идентификаторов.
Вы тестируете свой сервис, поэтому вам следует имитировать его зависимости, такие как репозиторий. Имитируя метод
save, вы можете указать объект, который он возвращает.