首页 > 解决方案 > 使用 mockito 为 findById() JPA 方法编写 Junit 测试用例时,我收到错误 java.util.NoSuchElementException: No value present

问题描述

由于 JPA 的 findById 方法的返回类型是可选的,并且我使用 get 方法来获取确切的值,因此我无法实现单元测试。

我的服务代码:

公共类 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 的返回类型更改为 Optional。在当前情况下是否有任何转机来编写测试?

标签: javajpajunitspring-data-jpamockito

解决方案


我将findById(id)方法更改getOne(id)为如下 -

Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);

并将我的测试用例更改为 -

Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);

它现在工作正常。


推荐阅读