web-dev-qa-db-ja.com

ユニットテストでJPAリポジトリの保存方法をモックする方法

たとえば、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();
}
_

次のロジックがあります:

  1. テスト開始
  2. User dbUser = userRepository.findOne(userDto.getId()); dbUser = NULL
  3. _if (dbUser != null_)およびif (oneByLogin != null) skip
  4. 新しいユーザーを作成してデータを設定する
  5. User savedUser = userRepository.save(newUser); savedUser = NULL

このステップでは、userRepository.save(newUser)をモックできないため、問題があります。

_newUser create inside the method. and test fail.
_

savedUser.getAuthToken()-savedUser == NULL

書き直すことができます:

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

しかし、返されたオブジェクトsavedUserを使用したい場合はどうなりますか?

8
ip696

次のことができます。

@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(UserDto.class)).thenReturn(userToReturnFromRepository);

     UserDto found = userService.create(userDtoRequest);

     // ... your asserts

  }

}

このアプローチでは、mockedUserRepositoryがテスト対象のクラス(コンストラクターなど)に挿入されることを確認する必要があります。

4
rieckpil

これを行う必要があります。

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

これで、引数として渡すユーザーを取得できます。

2
spajdo

異なるシナリオをテストするには、複数のテストケースを作成する必要があります。

シナリオ1:findOneがnull以外のオブジェクトを返す場合:

@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がnullオブジェクトを返す場合:

@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:saveが完了した場合:

@テスト

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());
}
0
codeLover