spring 如何在单元测试中模拟JPA存储库的保存方法

mf98qq94  于 2024-01-05  发布在  Spring
关注(0)|答案(5)|浏览(114)

例如,我在UserService中有这样的方法:

  1. @Override
  2. @Transactional
  3. public UserDto create(UserDto userDto) {
  4. User dbUser = userRepository.findOne(userDto.getId());
  5. if (dbUser != null) {
  6. throw new AuthException(AuthException.ErrorCode.DUPLICATE_USER_EXCEPTION);
  7. }
  8. User oneByLogin = userRepository.findOneByLogin(userDto.getLogin());
  9. if (oneByLogin != null) {
  10. throw new AuthExceptionAuthException.ErrorCode.DUPLICATE_LOGIN_EXCEPTION);
  11. }
  12. User newUser = new User();
  13. newUser.setGuid(UUID.randomUUID().toString());
  14. newUser.setInsertDate(new Date());
  15. newUser.setFirstName(userDto.getFirstName());
  16. newUser.setLastName(userDto.getLastName());
  17. newUser.setLogin(userDto.getLogin());
  18. newUser.setPassword(userDto.getPassword());
  19. newUser.setAuthToken(TokenGenerator.nextToken());
  20. newUser.setAuthTokenCreatedDate(new Date());
  21. User savedUser = userRepository.save(newUser);
  22. userDto.setAuthToken(savedUser.getAuthToken());
  23. log.info("User {0} created", savedUser.getLogin());
  24. return userDto;
  25. }

字符串
如何为这个方法创建单元测试?我尝试了下面的方法:

  1. @Test
  2. public void createUser() {
  3. UserDto userDtoRequest = new UserDto();
  4. userDtoRequest.setLogin("Alex");
  5. userDtoRequest.setPassword("123");
  6. UserDto found = userService.create(userDtoRequest);
  7. assertThat(found.getAuthToken()).isNotEmpty();
  8. }


我有下一个逻辑:
1.测试开始

  1. User dbUser = userRepository.findOne(userDto.getId()); dbUser = NULL
  2. if (dbUser != null)和if (oneByLogin != null)跳过
    1.创建新用户并设置数据
  3. User savedUser = userRepository.save(newUser); savedUser = NULL
    在这一步中,我遇到了一个问题,因为我不能模拟userRepository.save(newUser)
  1. newUser create inside the method. and test fail.


savedUser.getAuthToken()- savedUser == NULL
我可以重写:

  1. userRepository.save(newUser);
  2. userDto.setAuthToken(newUser.getAuthToken());
  3. log.info("User {0} created", newUser.getLogin());
  4. return userDto;


但是如果我想使用返回的对象savedUser呢?

f45qwnt8

f45qwnt81#

你必须这么做

  1. when(userRepository.save(Mockito.any(User.class)))
  2. .thenAnswer(i -> i.getArguments()[0]);

字符串
现在你可以获取user,并将其作为参数传递。

e0bqpujr

e0bqpujr2#

您可以执行以下操作:

  1. @RunWith(MockitoJUnitRunner.class)
  2. public class SimpleTest {
  3. @Mock
  4. private UserRepository mockedUserRepository;
  5. // .. your test setup
  6. @Test
  7. public void testYourMethod() {
  8. User userToReturnFromRepository = new User();
  9. userToReturnFromRepository.setAuthToken(YOUR_TOKEN);
  10. when(mockedUserRepository.save(any(User.class)).thenReturn(userToReturnFromRepository);
  11. UserDto found = userService.create(userDtoRequest);
  12. // ... your asserts
  13. }
  14. }

字符串
使用这种方法,你只需要确保你的mockedUserRepository被注入到你的测试类中(例如,在构造函数中)。

展开查看全部
yuvru6vn

yuvru6vn3#

您需要编写多个测试用例来测试不同的场景。
场景1:当findOne返回非空对象时:

  1. @Test(expected=AuthException.class)
  2. public void testCreateUserWhenAvailable() {
  3. //Create one sample userDto object with test data
  4. when(mockedUserRepository.findOne(userDto.getId())).thenReturn(new User());
  5. userService.create(userDto);
  6. }

字符串
场景二:findOneByLogin返回null对象:

  1. @Test(expected=AuthException.class)
  2. public void testCreateUserWhenLoginAvailable() {
  3. //Create one sample userDto object with test data
  4. when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
  5. when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(new User());
  6. userService.create(userDto);
  7. }


场景二:保存完成时:
@测试

  1. public void testCreateUserWhenSaved() {
  2. //Create one sample userDto object with test data
  3. when(mockedUserRepository.findOne(userDto.getId())).thenReturn(null);
  4. when(mockedUserRepository.findOneByLogin(userDto.getId())).thenReturn(null);
  5. //Create sample User object and set all the properties
  6. User newUser=new User();
  7. when(mockedUserRepository.save(Mockito.any(User.class)).thenReturn(newUser);
  8. User returnedUser=userService.create(userDto);
  9. //You have two ways to test, you can either verify that save method was invoked by
  10. //verify method
  11. verify(mockedUserRepository, times(1)).save(Mockito.any(User.class));
  12. //or by assertion statements, match the authToken in the returned object to be equal
  13. //to the one set by you in the mocked object
  14. Assert.assertEquals(returnedUser.getAuthToken(),newUser.getAuthToken());
  15. }

展开查看全部
r6hnlfcb

r6hnlfcb4#

关于如何创建JPA存储库save方法,为@GeneratedValue字段生成随机ID,我只说两句。

  1. /**
  2. * Mocks {@link JpaRepository#save(Object)} method to return the
  3. * saved entity as it was passed as parameter and add generated ID to it.
  4. * If ID could not be generated, it will be ignored.
  5. * If parameter already has and ID, it will be overridden.
  6. */
  7. private <T, V> void mockSave(JpaRepository<T, V> repository) {
  8. when(repository.save(any())).thenAnswer(i -> {
  9. Object argument = i.getArgument(0);
  10. Arrays.stream(argument.getClass().getDeclaredFields())
  11. .filter(f -> f.getAnnotation(GeneratedValue.class) != null)
  12. .forEach(f -> enrichGeneratedValueField(argument, f));
  13. return argument;
  14. });
  15. }

字符串
因此,这里您将所需的存储库作为参数传递,并且方法为所有使用@GeneratedValue annotation注解的字段调用enrichGeneratedValueField。下面是此方法的实现:

  1. private void enrichGeneratedValueField(Object argument, Field field) {
  2. try {
  3. if (field.getType().isAssignableFrom(Integer.class)) {
  4. FieldUtils.writeField(field, argument, Math.abs(random.nextInt()), true);
  5. } else {
  6. FieldUtils.writeField(field, argument, mock(field.getType()), true);
  7. }
  8. } catch (Exception ignored) {
  9. }
  10. }


在这个例子中,我只使用了Integer类型的ID,但是可以自由地添加你想要的ID类型。

展开查看全部
7fhtutme

7fhtutme5#

要验证保存是否成功,也可以尝试以下操作

  1. verify(repository, never()).save(savedEntity)

字符串

相关问题