From c26321f797ba7e436d4442f614b9a22a3a72cadd Mon Sep 17 00:00:00 2001 From: 5803024019 Date: Sat, 16 May 2026 08:10:41 +0700 Subject: [PATCH] test: add AuthControllerTest unit test --- .../Controller/AuthControllerTest.java | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 walkguide-backend/demo/src/test/java/com/walkguide/Controller/AuthControllerTest.java diff --git a/walkguide-backend/demo/src/test/java/com/walkguide/Controller/AuthControllerTest.java b/walkguide-backend/demo/src/test/java/com/walkguide/Controller/AuthControllerTest.java new file mode 100644 index 0000000..8f703ba --- /dev/null +++ b/walkguide-backend/demo/src/test/java/com/walkguide/Controller/AuthControllerTest.java @@ -0,0 +1,262 @@ +package com.walkguide.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.walkguide.dto.request.FcmTokenRequest; +import com.walkguide.dto.request.LoginRequest; +import com.walkguide.dto.request.RefreshTokenRequest; +import com.walkguide.dto.request.RegisterRequest; +import com.walkguide.dto.response.AuthDataResponse; +import com.walkguide.security.SecurityHelper; +import com.walkguide.service.AuthService; +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.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +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(AuthController.class) +@DisplayName("AuthController Unit Tests") +class AuthControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private AuthService authService; + + private AuthDataResponse sampleAuthData; + + @BeforeEach + void setUp() { + sampleAuthData = AuthDataResponse.builder() + .accessToken("access-token-xyz") + .refreshToken("refresh-token-xyz") + .role("ROLE_USER") + .userId(1L) + .displayName("Test User") + .uniqueUserId("ABC123DEF456") + .build(); + } + + // ===== PING ===== + + @Test + @DisplayName("GET /api/v1/auth/ping - harus return 200 pong") + void ping_shouldReturn200WithPong() throws Exception { + mockMvc.perform(get("/api/v1/auth/ping")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data").value("pong")) + .andExpect(jsonPath("$.message").value("Server aktif")); + } + + // ===== REGISTER ===== + + @Test + @DisplayName("POST /api/v1/auth/register - valid request harus return 200 dengan token") + void register_validRequest_shouldReturn200() throws Exception { + RegisterRequest req = new RegisterRequest(); + req.setEmail("new@test.com"); + req.setPassword("password123"); + req.setDisplayName("New User"); + req.setRole("USER"); + + when(authService.register(any(RegisterRequest.class))).thenReturn(sampleAuthData); + + mockMvc.perform(post("/api/v1/auth/register") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.message").value("Registrasi berhasil")) + .andExpect(jsonPath("$.data.accessToken").value("access-token-xyz")) + .andExpect(jsonPath("$.data.role").value("ROLE_USER")); + + verify(authService).register(any(RegisterRequest.class)); + } + + @Test + @DisplayName("POST /api/v1/auth/register - email kosong harus return 400") + void register_emptyEmail_shouldReturn400() throws Exception { + RegisterRequest req = new RegisterRequest(); + req.setEmail(""); + req.setPassword("password123"); + req.setDisplayName("New User"); + req.setRole("USER"); + + mockMvc.perform(post("/api/v1/auth/register") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isBadRequest()); + + verify(authService, never()).register(any()); + } + + @Test + @DisplayName("POST /api/v1/auth/register - password kurang dari 6 karakter harus return 400") + void register_shortPassword_shouldReturn400() throws Exception { + RegisterRequest req = new RegisterRequest(); + req.setEmail("user@test.com"); + req.setPassword("abc"); + req.setDisplayName("User"); + req.setRole("USER"); + + mockMvc.perform(post("/api/v1/auth/register") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isBadRequest()); + + verify(authService, never()).register(any()); + } + + @Test + @DisplayName("POST /api/v1/auth/register - format email tidak valid harus return 400") + void register_invalidEmailFormat_shouldReturn400() throws Exception { + RegisterRequest req = new RegisterRequest(); + req.setEmail("bukan-email"); + req.setPassword("password123"); + req.setDisplayName("User"); + req.setRole("USER"); + + mockMvc.perform(post("/api/v1/auth/register") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isBadRequest()); + + verify(authService, never()).register(any()); + } + + // ===== LOGIN ===== + + @Test + @DisplayName("POST /api/v1/auth/login - valid credentials harus return 200 dengan token") + void login_validCredentials_shouldReturn200() throws Exception { + LoginRequest req = new LoginRequest(); + req.setEmail("user@test.com"); + req.setPassword("password123"); + + when(authService.login(any(LoginRequest.class))).thenReturn(sampleAuthData); + + mockMvc.perform(post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.message").value("Login berhasil")) + .andExpect(jsonPath("$.data.accessToken").value("access-token-xyz")) + .andExpect(jsonPath("$.data.userId").value(1)); + + verify(authService).login(any(LoginRequest.class)); + } + + @Test + @DisplayName("POST /api/v1/auth/login - service throw RuntimeException harus return 500") + void login_serviceThrows_shouldReturn500() throws Exception { + LoginRequest req = new LoginRequest(); + req.setEmail("user@test.com"); + req.setPassword("wrong"); + + when(authService.login(any(LoginRequest.class))) + .thenThrow(new RuntimeException("Password salah")); + + mockMvc.perform(post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isInternalServerError()); + } + + // ===== REFRESH ===== + + @Test + @DisplayName("POST /api/v1/auth/refresh - token valid harus return token baru") + void refresh_validToken_shouldReturn200() throws Exception { + RefreshTokenRequest req = new RefreshTokenRequest(); + req.setRefreshToken("valid-refresh-token"); + + AuthDataResponse newData = AuthDataResponse.builder() + .accessToken("new-access-token") + .refreshToken("valid-refresh-token") + .role("ROLE_USER") + .userId(1L) + .build(); + + when(authService.refreshToken("valid-refresh-token")).thenReturn(newData); + + mockMvc.perform(post("/api/v1/auth/refresh") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.message").value("Token diperbarui")) + .andExpect(jsonPath("$.data.accessToken").value("new-access-token")); + + verify(authService).refreshToken("valid-refresh-token"); + } + + // ===== LOGOUT ===== + + @Test + @DisplayName("POST /api/v1/auth/logout - authenticated user harus return 200") + @WithMockUser(username = "1", roles = "USER") + void logout_authenticated_shouldReturn200() throws Exception { + try (MockedStatic securityHelper = mockStatic(SecurityHelper.class)) { + securityHelper.when(SecurityHelper::getCurrentUserId).thenReturn(1L); + doNothing().when(authService).logout(1L); + + mockMvc.perform(post("/api/v1/auth/logout") + .with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.message").value("Logout berhasil")); + + verify(authService).logout(1L); + } + } + + // ===== UPDATE FCM TOKEN ===== + + @Test + @DisplayName("PUT /api/v1/auth/fcm-token - authenticated user harus update FCM token") + @WithMockUser(username = "1", roles = "USER") + void updateFcmToken_authenticated_shouldReturn200() throws Exception { + try (MockedStatic securityHelper = mockStatic(SecurityHelper.class)) { + securityHelper.when(SecurityHelper::getCurrentUserId).thenReturn(1L); + + FcmTokenRequest req = new FcmTokenRequest(); + req.setFcmToken("fcm-token-new-value"); + + doNothing().when(authService).updateFcmToken(eq(1L), eq("fcm-token-new-value")); + + mockMvc.perform(put("/api/v1/auth/fcm-token") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.message").value("FCM token diperbarui")); + + verify(authService).updateFcmToken(1L, "fcm-token-new-value"); + } + } +}