Added tests for all services and controller

This commit is contained in:
lobo committed 2026-04-04 16:01:05 +02:00
1 parent c028e8d382
commit ad30de4190
7 files changed
+367 -21

No files matched your search

@@ -6,6 +6,7 @@ import auth_service.domain.login.exception.UserNotFoundException;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -14,15 +15,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
@Order(value = 1) @Order(value = 1)
@Slf4j @Slf4j
public class LoginExceptionController { public class LoginExceptionController {
private static @NonNull ResponseEntity<ErrorResponse> response500(ErrorResponse body) { private static @NonNull ResponseEntity<ErrorResponse> response(ErrorResponse body, HttpStatus status) {
log.error(body.message(), body.code()); return ResponseEntity.status(status.value())
return ResponseEntity.status(500)
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
.body(body);
}
private static @NonNull ResponseEntity<ErrorResponse> response400(ErrorResponse body) {
return ResponseEntity.status(400)
.contentType(org.springframework.http.MediaType.APPLICATION_JSON) .contentType(org.springframework.http.MediaType.APPLICATION_JSON)
.body(body); .body(body);
} }
@@ -37,12 +31,12 @@ public class LoginExceptionController {
@ExceptionHandler(UserNotFoundException.class) @ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> clientError(UserNotFoundException ex) { public ResponseEntity<ErrorResponse> clientError(UserNotFoundException ex) {
var body = new ErrorResponse("USER_NOT_FOUND", ex.getMessage()); var body = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
return response400(body); return response(body, HttpStatus.NOT_ACCEPTABLE);
} }
@ExceptionHandler(InvalidCredentialsException.class) @ExceptionHandler(InvalidCredentialsException.class)
public ResponseEntity<ErrorResponse> clientError(InvalidCredentialsException ex) { public ResponseEntity<ErrorResponse> clientError(InvalidCredentialsException ex) {
var body = new ErrorResponse("INVALID_CREDENTIALS", ex.getMessage()); var body = new ErrorResponse("INVALID_CREDENTIALS", ex.getMessage());
return response400(body); return response(body, HttpStatus.UNAUTHORIZED);
} }
} }
@@ -5,6 +5,7 @@ import auth_service.domain.user.exception.UserNotFoundException;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -13,15 +14,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
@Order(value = 1) @Order(value = 1)
@Slf4j @Slf4j
public class UserExceptionController { public class UserExceptionController {
private static @NonNull ResponseEntity<ErrorResponse> response500(ErrorResponse body) { private static @NonNull ResponseEntity<ErrorResponse> response(ErrorResponse body, HttpStatus status) {
log.error(body.message(), body.code()); return ResponseEntity.status(status.value())
return ResponseEntity.status(500)
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
.body(body);
}
private static @NonNull ResponseEntity<ErrorResponse> response400(ErrorResponse body) {
return ResponseEntity.status(400)
.contentType(org.springframework.http.MediaType.APPLICATION_JSON) .contentType(org.springframework.http.MediaType.APPLICATION_JSON)
.body(body); .body(body);
} }
@@ -36,7 +30,7 @@ public class UserExceptionController {
@ExceptionHandler(UserNotFoundException.class) @ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> clientError(UserNotFoundException ex) { public ResponseEntity<ErrorResponse> clientError(UserNotFoundException ex) {
var body = new ErrorResponse("USER_NOT_FOUND", ex.getMessage()); var body = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
return response400(body); return response(body, HttpStatus.NOT_FOUND);
} }
} }
@@ -0,0 +1,79 @@
package auth_service.configuration.security;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
/**
* Tests for JwtService.
*/
@ExtendWith(MockitoExtension.class)
class JwtServiceTest {
@Mock
private JwtConfig jwtConfig;
private JwtService jwtService;
@BeforeEach
void setUp() {
when(jwtConfig.getSecret()).thenReturn("verysecretkeythatmustbeatleast32characterslongforhmacsha");
jwtService = new JwtService(jwtConfig);
}
@Test
void generateToken_Success() {
// Arrange
var email = "test@example.com";
// Act
var token = jwtService.generateToken(email);
// Assert
assertNotNull(token);
assertFalse(token.isEmpty());
}
@Test
void extractEmail_Success() {
// Arrange
var email = "test@example.com";
var token = jwtService.generateToken(email);
// Act
var extractedEmail = jwtService.extractEmail(token);
// Assert
assertEquals(email, extractedEmail);
}
@Test
void isTokenValid_Success() {
// Arrange
var email = "test@example.com";
var token = jwtService.generateToken(email);
// Act
var isValid = jwtService.isTokenValid(token);
// Assert
assertTrue(isValid);
}
@Test
void isTokenValid_Failure() {
// Arrange
var invalidToken = "invalid-token";
// Act
var isValid = jwtService.isTokenValid(invalidToken);
// Assert
assertFalse(isValid);
}
}
@@ -0,0 +1,77 @@
package auth_service.domain.login.controller;
import auth_service.configuration.security.JwtAuthenticationFilter;
import auth_service.configuration.security.JwtService;
import auth_service.domain.login.controller.dto.request.LoginRequest;
import auth_service.domain.login.exception.InvalidCredentialsException;
import auth_service.domain.login.model.User;
import auth_service.domain.login.service.LoginService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
import org.springframework.boot.test.json.JacksonTester;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for LoginController.
*/
@WebMvcTest(LoginController.class)
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
@AutoConfigureJsonTesters
class LoginControllerTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private LoginService loginService;
@MockitoBean
private JwtService jwtService;
@MockitoBean
private JwtAuthenticationFilter jwtAuthenticationFilter; // Needed because it's used in SecurityConfig
@Autowired
private JacksonTester<LoginRequest> loginRequestJson;
@Test
void login_Success() throws Exception {
// Arrange
var request = new LoginRequest("test@example.com", "password");
var authenticatedUser = User.builder().email("test@example.com").build();
when(loginService.login(any(User.class))).thenReturn(authenticatedUser);
when(jwtService.generateToken("test@example.com")).thenReturn("mock-token");
// Act & Assert
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(loginRequestJson.write(request).getJson()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Login successful"))
.andExpect(jsonPath("$.token").value("mock-token"));
}
@Test
void login_Failure() throws Exception {
// Arrange
var request = new LoginRequest("test@example.com", "wrong-password");
when(loginService.login(any(User.class))).thenThrow(new InvalidCredentialsException("Invalid credentials"));
// Act & Assert
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(loginRequestJson.write(request).getJson()))
.andExpect(status().isUnauthorized());
}
}
@@ -0,0 +1,85 @@
package auth_service.domain.login.service;
import auth_service.domain.login.exception.InvalidCredentialsException;
import auth_service.domain.login.exception.UserNotFoundException;
import auth_service.domain.login.model.User;
import auth_service.domain.login.persistence.MinimalUserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
/**
* Tests for LoginService.
*/
@ExtendWith(MockitoExtension.class)
class LoginServiceTest {
@Mock
private MinimalUserRepository minimalUserRepository;
@Mock
private PasswordEncoder passwordEncoder;
@InjectMocks
private LoginService loginService;
private User user;
@BeforeEach
void setUp() {
user = User.builder()
.email("test@example.com")
.password("password")
.build();
}
@Test
void login_Success() {
// Arrange
var dbUser = User.builder()
.email("test@example.com")
.password("encodedPassword")
.build();
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(true);
// Act
var result = loginService.login(user);
// Assert
assertEquals(dbUser, result);
}
@Test
void login_UserNotFound() {
// Arrange
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.empty());
// Act & Assert
assertThrows(UserNotFoundException.class, () -> loginService.login(user));
}
@Test
void login_InvalidCredentials() {
// Arrange
var dbUser = User.builder()
.email("test@example.com")
.password("encodedPassword")
.build();
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(false);
// Act & Assert
assertThrows(InvalidCredentialsException.class, () -> loginService.login(user));
}
}
@@ -0,0 +1,64 @@
package auth_service.domain.user.controller;
import auth_service.configuration.security.JwtAuthenticationFilter;
import auth_service.configuration.security.JwtService;
import auth_service.domain.user.exception.UserNotFoundException;
import auth_service.domain.user.model.User;
import auth_service.domain.user.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(UserController.class)
@AutoConfigureMockMvc(addFilters = false)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private UserService userService;
@MockitoBean
private JwtService jwtService;
@MockitoBean
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Test
void getCurrentUserV1_Success() throws Exception {
// Arrange
var email = "test@example.com";
var user = User.builder().email(email).build();
when(userService.getUserByEmail(email)).thenReturn(user);
// Act & Assert
mockMvc.perform(get("/api/users/me")
.principal(() -> email)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.email").value(email));
}
@Test
void getCurrentUserV1_NotFound() throws Exception {
// Arrange
var email = "notfound@example.com";
when(userService.getUserByEmail(email)).thenThrow(new UserNotFoundException("User not found"));
// Act & Assert
mockMvc.perform(get("/api/users/me")
.principal(() -> email)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
}
}
@@ -0,0 +1,53 @@
package auth_service.domain.user.service;
import auth_service.domain.user.exception.UserNotFoundException;
import auth_service.domain.user.model.User;
import auth_service.domain.user.persistence.UserRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
/**
* Tests for UserService.
*/
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUserByEmail_Success() {
// Arrange
var email = "test@example.com";
var user = User.builder().email(email).build();
when(userRepository.findByEmail(email)).thenReturn(Optional.of(user));
// Act
var result = userService.getUserByEmail(email);
// Assert
assertEquals(user, result);
}
@Test
void getUserByEmail_NotFound() {
// Arrange
var email = "notfound@example.com";
when(userRepository.findByEmail(email)).thenReturn(Optional.empty());
// Act & Assert
assertThrows(UserNotFoundException.class, () -> userService.getUserByEmail(email));
}
}