test: add UserControllerTest unit test

This commit is contained in:
5803024019 2026-05-16 08:17:27 +07:00
parent efd8560324
commit f9a23dee58

View File

@ -0,0 +1,391 @@
package com.walkguide.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.walkguide.dto.ApiResponse;
import com.walkguide.dto.request.*;
import com.walkguide.dto.response.*;
import com.walkguide.entity.User;
import com.walkguide.enums.ActivityLogType;
import com.walkguide.repository.UserRepository;
import com.walkguide.security.SecurityHelper;
import com.walkguide.service.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import java.util.Optional;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserController.class)
@WithMockUser(username = "1", roles = "USER")
@DisplayName("UserController Unit Tests")
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean private LocationService locationService;
@MockBean private ObstacleLogService obstacleLogService;
@MockBean private SosService sosService;
@MockBean private ActivityLogService activityLogService;
@MockBean private NotificationService notificationService;
@MockBean private UserSettingsService userSettingsService;
@MockBean private AiConfigService aiConfigService;
@MockBean private VoiceCommandService voiceCommandService;
@MockBean private HardwareShortcutService hardwareShortcutService;
@MockBean private UserRepository userRepository;
private User sampleUser;
@BeforeEach
void setUp() {
sampleUser = User.builder()
.id(1L)
.email("user@test.com")
.displayName("Test User")
.role("ROLE_USER")
.uniqueUserId("ABC123DEF456")
.build();
}
// ===== PROFILE =====
@Test
@DisplayName("GET /api/v1/user/profile - harus return profil user")
void getProfile_shouldReturn200WithProfile() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
mockMvc.perform(get("/api/v1/user/profile"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.email").value("user@test.com"))
.andExpect(jsonPath("$.data.uniqueUserId").value("ABC123DEF456"));
}
}
@Test
@DisplayName("GET /api/v1/user/profile - user tidak ditemukan harus return 500")
void getProfile_userNotFound_shouldReturn500() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(99L);
when(userRepository.findById(99L)).thenReturn(Optional.empty());
mockMvc.perform(get("/api/v1/user/profile"))
.andExpect(status().isInternalServerError());
}
}
// ===== SETTINGS =====
@Test
@DisplayName("GET /api/v1/user/settings - harus return settings user")
void getSettings_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
UserSettingsResponse settings = new UserSettingsResponse();
when(userSettingsService.getSettings(1L)).thenReturn(settings);
mockMvc.perform(get("/api/v1/user/settings"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Settings user"));
}
}
@Test
@DisplayName("PUT /api/v1/user/settings - harus update dan return settings baru")
void updateSettings_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
UserSettingsUpdateRequest req = new UserSettingsUpdateRequest();
UserSettingsResponse updated = new UserSettingsResponse();
when(userSettingsService.updateSettings(eq(1L), any())).thenReturn(updated);
mockMvc.perform(put("/api/v1/user/settings")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Settings diperbarui"));
verify(userSettingsService).updateSettings(eq(1L), any(UserSettingsUpdateRequest.class));
}
}
// ===== VOICE COMMANDS =====
@Test
@DisplayName("GET /api/v1/user/voice-commands - harus return list voice commands")
void getVoiceCommands_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
VoiceCommandResponse cmd = new VoiceCommandResponse();
when(voiceCommandService.getAll(1L)).thenReturn(List.of(cmd));
mockMvc.perform(get("/api/v1/user/voice-commands"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isArray());
}
}
// ===== SHORTCUTS =====
@Test
@DisplayName("GET /api/v1/user/shortcuts - harus return list shortcuts")
void getShortcuts_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(hardwareShortcutService.getAll(1L)).thenReturn(List.of());
mockMvc.perform(get("/api/v1/user/shortcuts"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true));
}
}
@Test
@DisplayName("PUT /api/v1/user/shortcuts - harus update shortcut")
void updateShortcut_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
HardwareShortcutUpdateRequest req = new HardwareShortcutUpdateRequest();
HardwareShortcutResponse resp = new HardwareShortcutResponse();
when(hardwareShortcutService.update(eq(1L), any())).thenReturn(resp);
mockMvc.perform(put("/api/v1/user/shortcuts")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Shortcut diperbarui"));
}
}
// ===== AI CONFIG =====
@Test
@DisplayName("GET /api/v1/user/ai-config - harus return AI config")
void getAiConfig_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(aiConfigService.getConfig(1L)).thenReturn(new AiConfigResponse());
mockMvc.perform(get("/api/v1/user/ai-config"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("AI config"));
}
}
// ===== LOCATION =====
@Test
@DisplayName("POST /api/v1/user/location - harus update lokasi dan return LocationResponse")
void updateLocation_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
LocationUpdateRequest req = new LocationUpdateRequest();
req.setLatitude(-7.2575);
req.setLongitude(112.7521);
LocationResponse resp = new LocationResponse();
when(locationService.updateLocation(eq(1L), any())).thenReturn(resp);
mockMvc.perform(post("/api/v1/user/location")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Lokasi diperbarui"));
verify(locationService).updateLocation(eq(1L), any(LocationUpdateRequest.class));
}
}
// ===== OBSTACLE =====
@Test
@DisplayName("POST /api/v1/user/obstacle - harus mencatat obstacle dan return response")
void logObstacle_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
ObstacleLogRequest req = new ObstacleLogRequest();
ObstacleLogResponse resp = new ObstacleLogResponse();
when(obstacleLogService.saveObstacle(eq(1L), any())).thenReturn(resp);
mockMvc.perform(post("/api/v1/user/obstacle")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Obstacle dicatat"));
}
}
// ===== SOS =====
@Test
@DisplayName("POST /api/v1/user/sos - harus trigger SOS dan return SosEventResponse")
void triggerSos_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
SosRequest req = new SosRequest();
SosEventResponse resp = new SosEventResponse();
when(sosService.triggerSos(eq(1L), any())).thenReturn(resp);
mockMvc.perform(post("/api/v1/user/sos")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("SOS dikirim! Guardian sudah diberitahu."));
verify(sosService).triggerSos(eq(1L), any(SosRequest.class));
}
}
// ===== ACTIVITY LOGS =====
@Test
@DisplayName("GET /api/v1/user/activity-logs - harus return paginated activity logs")
void getActivityLogs_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
Page<ActivityLogResponse> page = new PageImpl<>(List.of());
when(activityLogService.getLogs(eq(1L), any(PageRequest.class))).thenReturn(page);
mockMvc.perform(get("/api/v1/user/activity-logs")
.param("page", "0")
.param("size", "10"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Log aktivitas"));
}
}
// ===== NOTIFICATIONS =====
@Test
@DisplayName("GET /api/v1/user/notifications - harus return paginated notifikasi")
void getNotifications_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
Page<NotificationResponse> page = new PageImpl<>(List.of());
when(notificationService.getNotifications(eq(1L), any())).thenReturn(page);
mockMvc.perform(get("/api/v1/user/notifications"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Notifikasi"));
}
}
@Test
@DisplayName("GET /api/v1/user/notifications/unread-count - harus return jumlah belum dibaca")
void getUnreadCount_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(notificationService.getUnreadCount(1L)).thenReturn(5L);
mockMvc.perform(get("/api/v1/user/notifications/unread-count"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").value(5))
.andExpect(jsonPath("$.message").value("Jumlah notifikasi belum dibaca"));
}
}
@Test
@DisplayName("PUT /api/v1/user/notifications/mark-all-read - harus mark semua sebagai dibaca")
void markAllRead_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
doNothing().when(notificationService).markAllRead(1L);
mockMvc.perform(put("/api/v1/user/notifications/mark-all-read")
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Semua notifikasi ditandai sudah dibaca"));
}
}
@Test
@DisplayName("PUT /api/v1/user/notifications/{id}/read - harus mark satu notifikasi sebagai dibaca")
void markOneRead_shouldReturn200() throws Exception {
doNothing().when(notificationService).markOneRead(42L);
mockMvc.perform(put("/api/v1/user/notifications/42/read")
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Notifikasi ditandai sudah dibaca"));
verify(notificationService).markOneRead(42L);
}
// ===== WALKGUIDE START / STOP =====
@Test
@DisplayName("POST /api/v1/user/walkguide/start - harus catat log WALKGUIDE_START")
void walkGuideStart_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
doNothing().when(activityLogService).createLog(any(), eq(ActivityLogType.WALKGUIDE_START), anyString(), any());
mockMvc.perform(post("/api/v1/user/walkguide/start")
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("WalkGuide dimulai"));
verify(activityLogService).createLog(eq(sampleUser), eq(ActivityLogType.WALKGUIDE_START), anyString(), any());
}
}
@Test
@DisplayName("POST /api/v1/user/walkguide/stop - harus catat log WALKGUIDE_STOP")
void walkGuideStop_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> sh = mockStatic(SecurityHelper.class)) {
sh.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
doNothing().when(activityLogService).createLog(any(), eq(ActivityLogType.WALKGUIDE_STOP), anyString(), any());
mockMvc.perform(post("/api/v1/user/walkguide/stop")
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("WalkGuide dihentikan"));
verify(activityLogService).createLog(eq(sampleUser), eq(ActivityLogType.WALKGUIDE_STOP), anyString(), any());
}
}
}