При написании тестового примера Junit с использованием mockito для метода JPA findById () я получаю ошибку как java .util.NoSuchElementException: значение отсутствует - PullRequest
0 голосов
/ 10 апреля 2020

Поскольку метод findById в JPA имеет тип возвращаемого значения как необязательный, и я использую метод get для получения точного значения, я не могу выполнить модульный тест.

Код моей службы:

publi c class LobbyService {

private final Logger log = LoggerFactory.getLogger(LobbyService.class);

private final LobbyRepository lobbyRepository;
private final UserRepository userRepository;

@Autowired
public LobbyService(@Qualifier("lobbyRepository") LobbyRepository lobbyRepository, @Qualifier("userRepository") UserRepository userRepository) {
    this.lobbyRepository = lobbyRepository;
    this.userRepository = userRepository;
}

public Lobby createLobby(Lobby newLobby){

    checkIfLobbyExist(newLobby);
    lobbyRepository.save(newLobby);

    return newLobby;

}

public void updateStatusOfLobby(long id, int status){
    Lobby lobby = getLobby(id);
    lobby.setStatus(status);
    saveOrUpdate(lobby);
}

public void saveOrUpdate(Lobby updateLobby){
    lobbyRepository.save(updateLobby);
}

public List<LobbyGetDTO> getAllLobbies(){
    List<Lobby> lobbyList = this.lobbyRepository.findAll();
    List<LobbyGetDTO> lobbyGetDTOList = new ArrayList<>();
    for(Lobby tempLobby:lobbyList){
        LobbyGetDTO lobbyGetDTO = DTOMapper.INSTANCE.convertEntityToLobbyGetDTO(tempLobby);
        lobbyGetDTOList.add(lobbyGetDTO);
    }
    return lobbyGetDTOList;
}

public void removePlayerFromLobby(long id, long userId){
    Lobby lobby = getLobby(id);
    String baseErrorMessage = "This player id is invalid. Please provide proper id";
    if(lobby.getPlayerIds().contains(userId)){
        lobby.getPlayerIds().remove(userId);
    }
    else{
        throw new LobbyException(baseErrorMessage);
    }

    saveOrUpdate(lobby);
}

public void addPlayerToLobby(long id, long userId){
    Lobby lobby = getLobby(id);

    if(lobby.getStatus()==1){
        throw new LobbyException("Game is in progress. You can't join lobby in the middle of the game. Please try later");
    }

    //Checking if the user exists before adding the user to lobby
    userRepository.findById(userId)
            .orElseThrow(
                    () -> new LobbyException(String.format("User with id: %d doesn't exist", userId))
            );
    String baseErrorMessage = "The lobby cannot have more than 7 player. Please join different lobby";

    //Size of lobby is limited to maximum of 7 players.
    if(lobby.getPlayerIds().size()>=7){
        throw new LobbyException(baseErrorMessage);
    }

    //Player should be unique in the lobby
    if(lobby.getPlayerIds().contains(userId)){
        baseErrorMessage = "Player already exists in the lobby";
        throw new LobbyException(baseErrorMessage);
    }
    lobby.getPlayerIds().add(userId);
    saveOrUpdate(lobby);
}

public Lobby getLobby(Long id){

    Lobby lobby = this.lobbyRepository.findById(id).get();

    String baseErrorMessage = "The lobby %d doesn't exist. Please check the lobby which you are joining";
    if(null == lobby){
        throw new LobbyException(baseErrorMessage);
    }
    return lobby;
}

public void checkIfLobbyExist(Lobby lobbyToBeCreated) {
    /*
    This method checks the uniqueness of the lobby by lobby name. If the lobby with the same name
    exists then it should not be created.
     */
    Lobby newLobby = lobbyRepository.findByName(lobbyToBeCreated.getName());

    String baseErrorMessage = "The provided %s is not unique. Therefore, the lobby could not be created!";
    if (null != newLobby) {
        throw new LobbyException(String.format(baseErrorMessage, "lobby name"));
    }
}

}

Мой код Junit:

public class LobbyServiceTest {


@Mock
LobbyRepository lobbyRepository;

@Mock
UserRepository userRepository;

@InjectMocks
LobbyService lobbyService;

private User testUser;
private Lobby lobbyTest;

@BeforeEach
public void setupLobby(){
    MockitoAnnotations.initMocks(this);

    lobbyTest = new Lobby();

    lobbyTest.setName("testLobby");
    lobbyTest.setHostPlayerId(1L);

    testUser = new User();
    testUser.setId(1L);
    testUser.setName("testName");
    testUser.setUsername("testUsername");

    // when -> any object is being save in the userRepository -> return the dummy testUser
    Mockito.when(userRepository.save(Mockito.any())).thenReturn(testUser);

    Mockito.when(lobbyRepository.save(Mockito.any())).thenReturn(lobbyTest);

}

@Test
public void createdLobby_validInputs_success(){
    Lobby createdLobby = lobbyService.createLobby(lobbyTest);

    Mockito.verify(lobbyRepository, Mockito.times(1)).save(Mockito.any());
    assertEquals(createdLobby.getId(),lobbyTest.getId());
    assertEquals(createdLobby.getName(),lobbyTest.getName());
    assertEquals(createdLobby.getHostPlayerId(),lobbyTest.getHostPlayerId());
}

@Test
public void createdLobbyExist_Exception(){
    lobbyService.createLobby(lobbyTest);

    Mockito.when(lobbyRepository.findByName(Mockito.any())).thenReturn(lobbyTest);

    assertThrows(LobbyException.class, ()->lobbyService.createLobby(lobbyTest));
}

@Test
public void addUserToLobbyWhenGameGoingOn(){

    lobbyTest.setStatus(1);
    lobbyService.createLobby(lobbyTest);

    Mockito.when(lobbyRepository.findById(Mockito.any())).thenReturn(java.util.Optional.ofNullable(lobbyTest));
    assertThrows(LobbyException.class,()->lobbyService.addPlayerToLobby(1L,1L));


}

@Test
public void addUserToLobby(){

    List<Long> playerList  = new ArrayList<>();
    Long[] longList = new Long[]{2L,3L,4L,5L,6L,7L};
    Collections.addAll(playerList,longList);
    lobbyTest.setPlayerIds(playerList);
    lobbyService.createLobby(lobbyTest);


    //Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
    Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(lobbyTest);
    Mockito.when(userRepository.findById(1L)).thenReturn(java.util.Optional.ofNullable(testUser));
    Mockito.when(lobbyRepository.save(Mockito.any(Lobby.class))).thenReturn(lobbyTest);
    lobbyService.addPlayerToLobby(1L,1L);
    assertEquals(lobbyTest.getPlayerIds().size(),7);

}

@Test
public void addExistingUserToLobby(){


    List<Long> playerList  = new ArrayList<>();
    Long[] longList = new Long[]{1L,3L,4L,5L,6L,7L};
    Collections.addAll(playerList,longList);
    lobbyTest.setPlayerIds(playerList);
    lobbyService.createLobby(lobbyTest);

    //Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
    Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(lobbyTest);
    Mockito.when(userRepository.findById(1L)).thenReturn(Optional.ofNullable(testUser));
    Mockito.when(lobbyRepository.save(Mockito.any(Lobby.class))).thenReturn(lobbyTest);
    assertThrows(LobbyException.class,()->lobbyService.addPlayerToLobby(1L,1L));


}

@Test
public void addMoreThanSevenPlayerToLobby(){

    List<Long> playerList  = new ArrayList<>();
    Long[] longList = new Long[]{1L,2L,3L,4L,5L,6L,7L};
    Collections.addAll(playerList,longList);
    lobbyTest.setPlayerIds(playerList);
    lobbyService.createLobby(lobbyTest);

    //Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
    Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(lobbyTest);
    Mockito.when(userRepository.findById(1L)).thenReturn(Optional.ofNullable(testUser));
    Mockito.when(lobbyRepository.save(Mockito.any(Lobby.class))).thenReturn(lobbyTest);
    assertThrows(LobbyException.class,()->lobbyService.addPlayerToLobby(1L,8L));

}

}

Сообщение об ошибке:

No value present
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:148)

Я не хочу менять тип возвращаемого значения на Необязательный для findById. Если в текущем сценарии есть какой-либо вариант написания теста?

Ответы [ 3 ]

0 голосов
/ 10 апреля 2020

Для проверки вы должны смоделировать иobbyRepository.findById (), и id. В вашем тестовом примере выполните:

Lobby mockedLobby = getConcreteLobby();
Optional<Lobby> optionalLobby = Optional.of(mockedLobby);
when(lobbyRepository.findbyId(anyLong())).thenReturn(optionalLobby);

Существуют и другие подходы, но, вероятно, это подойдет для вашего сценария.

Еще одна вещь: вы не должны тестировать Optional, как вы это делали. Вы должны убедиться, что код возвращает Optional - пусто или нет - и иметь дело с ним, проверяя Optional.isPresent (). В вашем случае, если вы действительно хотите проверить на null, используйте getOrElse (null) вместо get ().

0 голосов
/ 10 апреля 2020

Я изменил метод findById (id) на getOne (id), как показано ниже -

Mockito.when (obbyRepository.getOne (anyLong ())). ThenReturn (obbyTest);

И изменил мой тестовый пример на -

Mockito.when (obbyRepository.getOne (anyLong ())). ThenReturn (obbyTest);

Теперь работает нормально.

0 голосов
/ 10 апреля 2020

Попробуйте заменить код теста на:

Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(Optional.ofNullable(lobbyTest));

...