英文:
When writing Junit test case using mockito for findById() JPA method I am getting error as java.util.NoSuchElementException: No value present
问题
自 findById 方法的 JPA 返回类型是 Optional,我正在使用 get 方法来获取确切的值,但我无法实现单元测试。
我的 Service 代码:
public class LobbyService {
// ...(你的其他代码部分)
public Lobby getLobby(Long id) {
Optional<Lobby> optionalLobby = this.lobbyRepository.findById(id);
if (optionalLobby.isPresent()) {
return optionalLobby.get();
} else {
throw new LobbyException(String.format("The lobby %d doesn't exist. Please check the lobby you are joining", id));
}
}
// ...(你的其他代码部分)
}
// ...(你的其他代码部分)
请注意,我只是翻译了部分代码以解决你的问题。如果你需要更多帮助,可以继续询问。
英文:
Since findById method of JPA has return type as optional and I am using get method to get the exact value, I am unable to implement unit test.
My Service code:
public 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"));
}
}
}
My Junit code:
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));
}
}
Error Message:
No value present
java.util.NoSuchElementException: No value present
at java.base/java.util.Optional.get(Optional.java:148)
I don't want to change my return type to Optional for findById. If there is any turnaround to write test in the current scenario?
答案1
得分: 0
尝试用以下代码替换你的测试代码:
Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(Optional.ofNullable(lobbyTest));
英文:
Try to replace your test code with:
Mockito.when(lobbyRepository.findById(anyLong())).thenReturn(Optional.ofNullable(lobbyTest));
答案2
得分: 0
你必须模拟 lobbyRepository.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()。
英文:
You must mock both lobbyRepository.findById() and id to test. In your test case, do:
Lobby mockedLobby = getConcreteLobby();
Optional<Lobby> optionalLobby = Optional.of(mockedLobby);
when(lobbyRepository.findbyId(anyLong())).thenReturn(optionalLobby);
There are other approaches, but this probably will make it for your scenario.
One more thing: you should not test an Optional as you did. You must assure the code returns an Optional - empty or not -, and deal with it testing for Optional.isPresent(). In your case, if you really want to test for null, use getOrElse(null) instead of get().
答案3
得分: 0
我将 findById(id)
方法更改为如下的 getOne(id)
方法 -
Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
并且将我的测试用例更改为 -
Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
现在正常运行。
英文:
I changed the findById(id)
method to getOne(id)
as below -
Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
And changed my test case to -
Mockito.when(lobbyRepository.getOne(anyLong())).thenReturn(lobbyTest);
Its working fine now.
答案4
得分: 0
Use doReturn(Optional.of(yourMockObj)).when(employeeRepository).findById(idToFind);
Sample Code
@Test
@Order(2)
@DisplayName("Test getEmployeeByEmployeeId")
public void test_getEmployeeByEmployeeId() throws EmployeeNotFoundException
{
// Setup the mock repo
Long employeeId = 1L;
Employee e1ForMock = new Employee(employeeId, "Aravinth P", 29, "aravinth.p@email.com");
doReturn(Optional.of(e1ForMock)).when(employeeRepository).findById(employeeId);
// Make the service call
Employee e1ByService = employeeServiceImpl.getEmployeeByEmployeeId(employeeId);
// Assert the response
assertNotNull(e1ByService, "Employee with employeeId : " + employeeId + " not found");
assertEquals(employeeId, e1ByService.getEmployeeId());
assertEquals(e1ForMock.getName(), e1ByService.getName());
assertEquals(e1ForMock.getAge(), e1ByService.getAge());
assertEquals(e1ForMock.getEmail(), e1ByService.getEmail());
}
英文:
Use doReturn(Optional.of(yourMockObj)).when(employeeRepository).findById(idToFind);
Sample Code
@Test
@Order(2)
@DisplayName("Test getEmployeeByEmployeeId")
public void test_getEmployeeByEmployeeId() throws EmployeeNotFoundException
{
// Setup the mock repo
Long employeeId = 1L;
Employee e1ForMock = new Employee(employeeId, "Aravinth P", 29, "aravinth.p@email.com");
doReturn(Optional.of(e1ForMock)).when(employeeRepository).findById(employeeId);
// Make the service call
Employee e1ByService = employeeServiceImpl.getEmployeeByEmployeeId(employeeId);
// Assert the response
assertNotNull(e1ByService,"Employee with employeeId : "+employeeId+" not found");
assertEquals(employeeId,e1ByService.getEmployeeId());
assertEquals(e1ForMock.getName(), e1ByService.getName());
assertEquals(e1ForMock.getAge(), e1ByService.getAge());
assertEquals(e1ForMock.getEmail(), e1ByService.getEmail());
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论