test: add AuthServiceTest - register & login

This commit is contained in:
5803024019 2026-05-15 21:29:26 +07:00
parent fa1c2ca69a
commit bfcfd4e0f5

View File

@ -0,0 +1,292 @@
package com.walkguide.service;
import com.walkguide.dto.request.LoginRequest;
import com.walkguide.dto.request.RegisterRequest;
import com.walkguide.dto.response.AuthDataResponse;
import com.walkguide.entity.RefreshToken;
import com.walkguide.entity.User;
import com.walkguide.entity.UserSettings;
import com.walkguide.enums.ActivityLogType;
import com.walkguide.repository.RefreshTokenRepository;
import com.walkguide.repository.UserRepository;
import com.walkguide.repository.UserSettingsRepository;
import com.walkguide.security.JwtUtil;
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.security.crypto.password.PasswordEncoder;
import java.time.LocalDateTime;
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("AuthService Unit Tests")
class AuthServiceTest {
@Mock UserRepository userRepository;
@Mock RefreshTokenRepository refreshTokenRepository;
@Mock UserSettingsRepository userSettingsRepository;
@Mock ActivityLogService activityLogService;
@Mock JwtUtil jwtUtil;
@Mock PasswordEncoder passwordEncoder;
@InjectMocks AuthService authService;
private User sampleUser;
private User sampleGuardian;
@BeforeEach
void setUp() {
sampleUser = User.builder()
.id(1L)
.email("user@test.com")
.password("encodedPassword")
.role("ROLE_USER")
.displayName("Test User")
.uniqueUserId("ABC123DEF456")
.build();
sampleGuardian = User.builder()
.id(2L)
.email("guardian@test.com")
.password("encodedPassword")
.role("ROLE_GUARDIAN")
.displayName("Test Guardian")
.build();
}
// ===== REGISTER TESTS =====
@Test
@DisplayName("register - ROLE_USER: harus generate uniqueUserId dan buat UserSettings")
void register_asUser_shouldGenerateUniqueUserIdAndCreateSettings() {
RegisterRequest req = new RegisterRequest();
req.setEmail("new@test.com");
req.setPassword("password123");
req.setDisplayName("New User");
req.setRole("USER");
when(userRepository.existsByEmail("new@test.com")).thenReturn(false);
when(userRepository.findByUniqueUserId(anyString())).thenReturn(Optional.empty());
when(passwordEncoder.encode("password123")).thenReturn("hashed");
when(userRepository.save(any(User.class))).thenAnswer(inv -> {
User u = inv.getArgument(0);
u.setId(10L);
return u;
});
when(jwtUtil.generateAccessToken(anyString(), anyString(), anyLong()))
.thenReturn("access-token");
when(jwtUtil.generateRefreshToken()).thenReturn("refresh-token");
when(refreshTokenRepository.save(any())).thenReturn(new RefreshToken());
AuthDataResponse result = authService.register(req);
assertThat(result).isNotNull();
assertThat(result.getRole()).isEqualTo("ROLE_USER");
assertThat(result.getAccessToken()).isEqualTo("access-token");
// Verifikasi UserSettings dibuat untuk ROLE_USER
verify(userSettingsRepository, times(1)).save(any(UserSettings.class));
}
@Test
@DisplayName("register - ROLE_GUARDIAN: tidak boleh generate uniqueUserId dan tidak buat UserSettings")
void register_asGuardian_shouldNotCreateUserSettings() {
RegisterRequest req = new RegisterRequest();
req.setEmail("guardian2@test.com");
req.setPassword("password123");
req.setDisplayName("New Guardian");
req.setRole("GUARDIAN");
when(userRepository.existsByEmail("guardian2@test.com")).thenReturn(false);
when(passwordEncoder.encode("password123")).thenReturn("hashed");
when(userRepository.save(any(User.class))).thenAnswer(inv -> {
User u = inv.getArgument(0);
u.setId(11L);
return u;
});
when(jwtUtil.generateAccessToken(anyString(), anyString(), anyLong()))
.thenReturn("access-token");
when(jwtUtil.generateRefreshToken()).thenReturn("refresh-token");
when(refreshTokenRepository.save(any())).thenReturn(new RefreshToken());
AuthDataResponse result = authService.register(req);
assertThat(result.getRole()).isEqualTo("ROLE_GUARDIAN");
// Tidak boleh buat UserSettings untuk Guardian
verify(userSettingsRepository, never()).save(any());
// Verifikasi uniqueUserId null pada Guardian
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
verify(userRepository).save(userCaptor.capture());
assertThat(userCaptor.getValue().getUniqueUserId()).isNull();
}
@Test
@DisplayName("register - email duplikat harus throw RuntimeException")
void register_duplicateEmail_shouldThrow() {
RegisterRequest req = new RegisterRequest();
req.setEmail("user@test.com");
req.setPassword("password123");
req.setDisplayName("User");
req.setRole("USER");
when(userRepository.existsByEmail("user@test.com")).thenReturn(true);
assertThatThrownBy(() -> authService.register(req))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("Email sudah terdaftar");
verify(userRepository, never()).save(any());
}
// ===== LOGIN TESTS =====
@Test
@DisplayName("login - credentials valid harus return AuthDataResponse")
void login_validCredentials_shouldReturnToken() {
LoginRequest req = new LoginRequest();
req.setEmail("user@test.com");
req.setPassword("correctPassword");
when(userRepository.findByEmail("user@test.com")).thenReturn(Optional.of(sampleUser));
when(passwordEncoder.matches("correctPassword", "encodedPassword")).thenReturn(true);
when(jwtUtil.generateAccessToken(anyString(), anyString(), anyLong()))
.thenReturn("access-token");
when(jwtUtil.generateRefreshToken()).thenReturn("refresh-token");
when(refreshTokenRepository.save(any())).thenReturn(new RefreshToken());
AuthDataResponse result = authService.login(req);
assertThat(result).isNotNull();
assertThat(result.getAccessToken()).isEqualTo("access-token");
assertThat(result.getRefreshToken()).isEqualTo("refresh-token");
assertThat(result.getUserId()).isEqualTo(1L);
// Harus hapus refresh token lama sebelum buat yang baru
verify(refreshTokenRepository).deleteByUserId(1L);
// Harus catat activity log LOGIN
verify(activityLogService).createLog(
eq(sampleUser), eq(ActivityLogType.LOGIN), anyString(), any());
}
@Test
@DisplayName("login - email tidak terdaftar harus throw RuntimeException")
void login_emailNotFound_shouldThrow() {
LoginRequest req = new LoginRequest();
req.setEmail("ghost@test.com");
req.setPassword("any");
when(userRepository.findByEmail("ghost@test.com")).thenReturn(Optional.empty());
assertThatThrownBy(() -> authService.login(req))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("Email tidak terdaftar");
}
@Test
@DisplayName("login - password salah harus throw RuntimeException")
void login_wrongPassword_shouldThrow() {
LoginRequest req = new LoginRequest();
req.setEmail("user@test.com");
req.setPassword("wrongPassword");
when(userRepository.findByEmail("user@test.com")).thenReturn(Optional.of(sampleUser));
when(passwordEncoder.matches("wrongPassword", "encodedPassword")).thenReturn(false);
assertThatThrownBy(() -> authService.login(req))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("Password salah");
}
// ===== REFRESH TOKEN TESTS =====
@Test
@DisplayName("refreshToken - token valid harus return access token baru")
void refreshToken_validToken_shouldReturnNewAccessToken() {
RefreshToken storedToken = RefreshToken.builder()
.token("valid-refresh-token")
.userId(1L)
.expiresAt(LocalDateTime.now().plusDays(10))
.build();
when(refreshTokenRepository.findByToken("valid-refresh-token"))
.thenReturn(Optional.of(storedToken));
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
when(jwtUtil.generateAccessToken(anyString(), anyString(), anyLong()))
.thenReturn("new-access-token");
AuthDataResponse result = authService.refreshToken("valid-refresh-token");
assertThat(result.getAccessToken()).isEqualTo("new-access-token");
// Refresh token tidak diganti tetap sama
assertThat(result.getRefreshToken()).isEqualTo("valid-refresh-token");
}
@Test
@DisplayName("refreshToken - token tidak ada di DB harus throw RuntimeException")
void refreshToken_invalidToken_shouldThrow() {
when(refreshTokenRepository.findByToken("fake-token")).thenReturn(Optional.empty());
assertThatThrownBy(() -> authService.refreshToken("fake-token"))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("Refresh token tidak valid");
}
@Test
@DisplayName("refreshToken - token kadaluarsa harus throw dan hapus dari DB")
void refreshToken_expiredToken_shouldThrowAndDelete() {
RefreshToken expiredToken = RefreshToken.builder()
.token("expired-token")
.userId(1L)
.expiresAt(LocalDateTime.now().minusDays(1)) // sudah lewat
.build();
when(refreshTokenRepository.findByToken("expired-token"))
.thenReturn(Optional.of(expiredToken));
assertThatThrownBy(() -> authService.refreshToken("expired-token"))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("kadaluarsa");
// Token kadaluarsa harus dihapus dari DB
verify(refreshTokenRepository).delete(expiredToken);
}
// ===== LOGOUT TESTS =====
@Test
@DisplayName("logout - harus hapus refresh token dan catat activity log")
void logout_shouldDeleteTokenAndLog() {
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
authService.logout(1L);
verify(refreshTokenRepository).deleteByUserId(1L);
verify(activityLogService).createLog(
eq(sampleUser), eq(ActivityLogType.LOGOUT), anyString(), any());
}
// ===== UPDATE FCM TOKEN TESTS =====
@Test
@DisplayName("updateFcmToken - harus update dan simpan fcmToken user")
void updateFcmToken_shouldSaveNewToken() {
when(userRepository.findById(1L)).thenReturn(Optional.of(sampleUser));
authService.updateFcmToken(1L, "new-fcm-token-xyz");
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(userRepository).save(captor.capture());
assertThat(captor.getValue().getFcmToken()).isEqualTo("new-fcm-token-xyz");
}
}