test: add ObstacleLogServiceTest unit test

This commit is contained in:
5803024019 2026-05-15 22:12:50 +07:00
parent 3eff1275f9
commit def12a1bdb

View File

@ -0,0 +1,212 @@
package com.walkguide.service;
import com.walkguide.dto.request.ObstacleLogRequest;
import com.walkguide.dto.response.ObstacleLogResponse;
import com.walkguide.entity.ObstacleLog;
import com.walkguide.entity.User;
import com.walkguide.enums.ActivityLogType;
import com.walkguide.exception.ResourceNotFoundException;
import com.walkguide.repository.ObstacleLogRepository;
import com.walkguide.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
@DisplayName("ObstacleLogService Unit Tests")
class ObstacleLogServiceTest {
@Mock
ObstacleLogRepository obstacleLogRepository;
@Mock
UserRepository userRepository;
@Mock
ActivityLogService activityLogService;
@InjectMocks
ObstacleLogService obstacleLogService;
private User sampleUser;
private ObstacleLogRequest sampleRequest;
@BeforeEach
void setUp() {
sampleUser = User.builder()
.id(5L)
.email("user@test.com")
.role("ROLE_USER")
.displayName("Test User")
.build();
sampleRequest = new ObstacleLogRequest();
sampleRequest.setLabel("Sepeda motor");
sampleRequest.setConfidence(0.92);
sampleRequest.setDirection("kiri");
sampleRequest.setEstimatedDist("1.5 meter");
sampleRequest.setLat(-7.2575);
sampleRequest.setLng(112.7521);
}
// ===== saveObstacle TESTS =====
@Test
@DisplayName("saveObstacle - harus simpan log dan return ObstacleLogResponse yang benar")
void saveObstacle_validRequest_shouldSaveAndReturnResponse() {
ObstacleLog savedLog = ObstacleLog.builder()
.id(1L)
.userId(5L)
.label("Sepeda motor")
.confidence(0.92)
.direction("kiri")
.estimatedDist("1.5 meter")
.lat(-7.2575)
.lng(112.7521)
.createdAt(LocalDateTime.now())
.build();
when(obstacleLogRepository.save(any(ObstacleLog.class))).thenReturn(savedLog);
when(userRepository.findById(5L)).thenReturn(Optional.of(sampleUser));
ObstacleLogResponse result = obstacleLogService.saveObstacle(5L, sampleRequest);
assertThat(result).isNotNull();
assertThat(result.getId()).isEqualTo(1L);
assertThat(result.getLabel()).isEqualTo("Sepeda motor");
assertThat(result.getConfidence()).isEqualTo(0.92);
assertThat(result.getDirection()).isEqualTo("kiri");
assertThat(result.getEstimatedDist()).isEqualTo("1.5 meter");
assertThat(result.getLat()).isEqualTo(-7.2575);
assertThat(result.getLng()).isEqualTo(112.7521);
}
@Test
@DisplayName("saveObstacle - harus simpan ObstacleLog dengan data dari request")
void saveObstacle_shouldPersistCorrectData() {
when(obstacleLogRepository.save(any(ObstacleLog.class)))
.thenAnswer(inv -> {
ObstacleLog log = inv.getArgument(0);
log = ObstacleLog.builder()
.id(10L).userId(log.getUserId()).label(log.getLabel())
.confidence(log.getConfidence()).direction(log.getDirection())
.estimatedDist(log.getEstimatedDist())
.lat(log.getLat()).lng(log.getLng()).build();
return log;
});
when(userRepository.findById(5L)).thenReturn(Optional.of(sampleUser));
obstacleLogService.saveObstacle(5L, sampleRequest);
ArgumentCaptor<ObstacleLog> captor = ArgumentCaptor.forClass(ObstacleLog.class);
verify(obstacleLogRepository).save(captor.capture());
ObstacleLog captured = captor.getValue();
assertThat(captured.getUserId()).isEqualTo(5L);
assertThat(captured.getLabel()).isEqualTo("Sepeda motor");
assertThat(captured.getConfidence()).isEqualTo(0.92);
assertThat(captured.getDirection()).isEqualTo("kiri");
}
@Test
@DisplayName("saveObstacle - harus mencatat OBSTACLE_DETECTED ke ActivityLog")
void saveObstacle_shouldCreateActivityLog() {
when(obstacleLogRepository.save(any(ObstacleLog.class)))
.thenReturn(ObstacleLog.builder().id(1L).label("Sepeda motor").direction("kiri").build());
when(userRepository.findById(5L)).thenReturn(Optional.of(sampleUser));
obstacleLogService.saveObstacle(5L, sampleRequest);
verify(activityLogService).createLog(
eq(sampleUser),
eq(ActivityLogType.OBSTACLE_DETECTED),
contains("Sepeda motor"),
anyString()
);
}
@Test
@DisplayName("saveObstacle - metadata ActivityLog harus mengandung label, direction, dan confidence")
void saveObstacle_activityLogMeta_shouldContainObstacleDetails() {
when(obstacleLogRepository.save(any(ObstacleLog.class)))
.thenReturn(ObstacleLog.builder().id(1L).label("Lubang").direction("depan").build());
when(userRepository.findById(5L)).thenReturn(Optional.of(sampleUser));
sampleRequest.setLabel("Lubang");
sampleRequest.setDirection("depan");
sampleRequest.setConfidence(0.85);
obstacleLogService.saveObstacle(5L, sampleRequest);
ArgumentCaptor<String> metaCaptor = ArgumentCaptor.forClass(String.class);
verify(activityLogService).createLog(any(), any(), any(), metaCaptor.capture());
String meta = metaCaptor.getValue();
assertThat(meta).contains("Lubang");
assertThat(meta).contains("depan");
assertThat(meta).contains("0.85");
}
@Test
@DisplayName("saveObstacle - user tidak ditemukan harus throw ResourceNotFoundException")
void saveObstacle_userNotFound_shouldThrow() {
when(obstacleLogRepository.save(any(ObstacleLog.class)))
.thenReturn(ObstacleLog.builder().id(1L).build());
when(userRepository.findById(99L)).thenReturn(Optional.empty());
assertThatThrownBy(() -> obstacleLogService.saveObstacle(99L, sampleRequest))
.isInstanceOf(ResourceNotFoundException.class)
.hasMessageContaining("User tidak ditemukan");
}
// ===== getObstacleLogs TESTS =====
@Test
@DisplayName("getObstacleLogs - harus return page dari ObstacleLogResponse")
void getObstacleLogs_shouldReturnPagedResponse() {
ObstacleLog log1 = ObstacleLog.builder().id(1L).userId(5L).label("Trotoar").confidence(0.80)
.direction("kanan").estimatedDist("2 meter").lat(-7.25).lng(112.75).build();
ObstacleLog log2 = ObstacleLog.builder().id(2L).userId(5L).label("Pohon").confidence(0.95)
.direction("depan").estimatedDist("1 meter").lat(-7.26).lng(112.76).build();
Page<ObstacleLog> page = new PageImpl<>(List.of(log1, log2));
Pageable pageable = PageRequest.of(0, 10);
when(obstacleLogRepository.findByUserIdOrderByCreatedAtDesc(5L, pageable)).thenReturn(page);
Page<ObstacleLogResponse> result = obstacleLogService.getObstacleLogs(5L, pageable);
assertThat(result.getContent()).hasSize(2);
assertThat(result.getContent().get(0).getLabel()).isEqualTo("Trotoar");
assertThat(result.getContent().get(1).getLabel()).isEqualTo("Pohon");
}
@Test
@DisplayName("getObstacleLogs - halaman kosong harus return page kosong tanpa error")
void getObstacleLogs_emptyPage_shouldReturnEmptyPage() {
Pageable pageable = PageRequest.of(0, 10);
when(obstacleLogRepository.findByUserIdOrderByCreatedAtDesc(5L, pageable))
.thenReturn(Page.empty());
Page<ObstacleLogResponse> result = obstacleLogService.getObstacleLogs(5L, pageable);
assertThat(result.getContent()).isEmpty();
assertThat(result.getTotalElements()).isZero();
}
}