Added new tests fixed some problem

This commit is contained in:
lobo committed 2026-04-18 11:28:06 +02:00
1 parent 14a4ccfb87
commit 20402eb7c4
32 files changed
+11120 -78

No files matched your search

+10713
View File
File diff suppressed because it is too large. Load diff
+5
View File
@@ -105,6 +105,11 @@
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
@@ -1,5 +1,6 @@
package auth_service.configuration.security;
import auth_service.domain.login.service.TokenGenerator;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;
@@ -12,7 +13,7 @@ import java.util.Date;
* Service responsible for generating and validating JSON Web Tokens (JWT).
*/
@Service
public class JwtService {
public class JwtService implements TokenGenerator {
// Token validity: 24 hours in milliseconds
private static final long JWT_EXPIRATION_MS = 86400000;
@@ -24,10 +25,10 @@ public class JwtService {
/**
* Generates a secure JWT for the authenticated user.
* * @param user The authenticated user entity
*
* @return A signed JWT string
*/
@Override
public String generateToken(String userId, String email) {
return Jwts.builder()
.subject(email)
@@ -1,6 +1,5 @@
package auth_service.domain.login.controller;
import auth_service.configuration.security.JwtService;
import auth_service.domain.login.controller.dto.request.LoginRequest;
import auth_service.domain.login.controller.dto.response.LoginResponse;
import auth_service.domain.login.controller.mapper.ApiMapper;
@@ -22,12 +21,11 @@ import org.springframework.web.bind.annotation.RestController;
public class LoginController {
private final LoginService loginService;
private final JwtService jwtService;
/**
* Authenticates a user based on email and password.
* * @param request The login credentials
*
* @param request The login credentials
* @return HTTP 200 on success, HTTP 401 on failure
*/
@PostMapping("/login")
@@ -35,8 +33,7 @@ public class LoginController {
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
var user = ApiMapper.toModel(request);
var authenticatedUser = loginService.login(user);
var token = jwtService.generateToken(authenticatedUser.getId() + "", authenticatedUser.getEmail());
var token = loginService.login(user);
return ResponseEntity.ok(new LoginResponse("Login successful", token));
}
}
@@ -1,6 +1,6 @@
package auth_service.domain.login.controller;
import auth_service.domain.login.controller.dto.response.ErrorResponse;
import auth_service.shared.controller.dto.response.ErrorResponse;
import auth_service.domain.login.exception.InvalidCredentialsException;
import auth_service.domain.login.exception.UserNotFoundException;
import lombok.NonNull;
@@ -1,4 +0,0 @@
package auth_service.domain.login.controller.dto.response;
public record ErrorResponse(String code, String message) {
}
@@ -15,19 +15,21 @@ import org.springframework.stereotype.Service;
public class LoginService {
private final MinimalUserRepository minimalUserRepository;
private final PasswordEncoder passwordEncoder;
private final TokenGenerator tokenGenerator;
/**
* Authenticates a user based on email and raw password.
* Authenticates a user and returns a token.
*
* @return The authenticated User model
* @return The generated token
*/
public User login(User userToLogin) {
var foundUser = minimalUserRepository.findByEmail(userToLogin.getEmail()).orElseThrow(() -> new UserNotFoundException("User not found with given email"));
public String login(User userToLogin) {
var foundUser = minimalUserRepository.findByEmail(userToLogin.getEmail())
.orElseThrow(() -> new UserNotFoundException("User not found with given email"));
var loginSuccessful = passwordEncoder.matches(userToLogin.getPassword(), foundUser.getPassword());
if (!loginSuccessful) {
throw new InvalidCredentialsException("Invalid credentials");
}
minimalUserRepository.updateLoginDate(foundUser.getId());
return foundUser;
return tokenGenerator.generateToken(String.valueOf(foundUser.getId()), foundUser.getEmail());
}
}
@@ -0,0 +1,16 @@
package auth_service.domain.login.service;
/**
* Port interface for token generation.
* Decouples the login service from specific token implementations (e.g. JWT).
*/
public interface TokenGenerator {
/**
* Generates a token for the given user.
*
* @param userId The unique identifier of the user.
* @param email The email address of the user.
* @return The generated token string.
*/
String generateToken(String userId, String email);
}
@@ -1,6 +1,6 @@
package auth_service.domain.registration.controller;
import auth_service.domain.registration.controller.dto.response.ErrorResponse;
import auth_service.shared.controller.dto.response.ErrorResponse;
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
import auth_service.domain.registration.exception.InvalidInvitationCodeException;
import auth_service.domain.registration.exception.SteamIdAlreadyRegisteredException;
@@ -1,4 +0,0 @@
package auth_service.domain.registration.controller.dto.response;
public record ErrorResponse(String code, String message) {
}
@@ -1,19 +1,19 @@
package auth_service.domain.registration.service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CodeValidationService {
private static final String RANDOM_INVITATION_CODE = "test-invite-code";
@Value("${auth.registration.invitation-code}")
private String invitationCode;
public boolean isCodeValid(String code) {
if (code == null || code.isEmpty()) {
return false;
}
return code.equals(RANDOM_INVITATION_CODE);
return code.equals(invitationCode);
}
}
@@ -1,6 +1,6 @@
package auth_service.domain.user.controller;
import auth_service.domain.user.controller.dto.response.ErrorResponse;
import auth_service.shared.controller.dto.response.ErrorResponse;
import auth_service.domain.user.exception.UserNotFoundException;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
@@ -1,4 +0,0 @@
package auth_service.domain.user.controller.dto.response;
public record ErrorResponse(String code, String message) {
}
@@ -0,0 +1,12 @@
package auth_service.shared.controller.dto.response;
import org.jspecify.annotations.NonNull;
/**
* Shared error response record for all domains.
*
* @param code A machine-readable error code.
* @param message A human-readable error message.
*/
public record ErrorResponse(@NonNull String code, @NonNull String message) {
}
+6 -1
View File
@@ -50,4 +50,9 @@ security:
app:
cors:
# Production default: strictly allow only the frontend domain
allowed-origins: "https://tbp.andreas-dahm.eu"
allowed-origins: "https://tbp.andreas-dahm.eu"
# Registration settings
auth:
registration:
invitation-code: ${AUTH_INVITATION_CODE}
@@ -1,25 +1,9 @@
package auth_service;
import auth_service.shared.test.AbstractIntegrationTest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@SpringBootTest
@Testcontainers
class AuthServiceApplicationTests {
/**
* Define the PostgreSQL container.
*
* @ServiceConnection automatically configures the application properties
* (URL, username, password) for this specific container.
*/
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17.9");
class AuthServiceApplicationTests extends AbstractIntegrationTest {
@Test
void contextLoads() {
@@ -1,5 +1,6 @@
package auth_service.architecture;
import auth_service.shared.test.AbstractArchitectureTest;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
@@ -14,7 +15,7 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
* Analyzes all classes in the 'auth_service' package, ignoring test classes.
*/
@AnalyzeClasses(packages = "auth_service", importOptions = ImportOption.DoNotIncludeTests.class)
class ArchitectureTest {
class ArchitectureTest extends AbstractArchitectureTest {
// ===================================================================================
// 1. DOMAIN INDEPENDENCE (Slices)
@@ -75,6 +76,24 @@ class ArchitectureTest {
.should().dependOnClassesThat().resideInAPackage("..persistence..")
.because("Controllers must delegate to Services and should not access Persistence directly.");
@ArchTest
static final ArchRule persistence_should_not_depend_on_controllers = noClasses()
.that().resideInAPackage("..persistence..")
.should().dependOnClassesThat().resideInAPackage("..controller..")
.because("Persistence layer must be independent of the Web/Controller layer.");
@ArchTest
static final ArchRule exceptions_should_be_isolated = noClasses()
.that().resideInAPackage("..exception..")
.should().dependOnClassesThat().resideInAnyPackage("..controller..", "..persistence.entities..")
.because("Exceptions should be part of the domain core and independent of infrastructure details.");
@ArchTest
static final ArchRule configuration_should_not_be_accessed_by_domain = noClasses()
.that().resideInAnyPackage("..domain..")
.should().dependOnClassesThat().resideInAPackage("auth_service.configuration..")
.because("Domain logic should not depend on Spring configuration classes.");
@ArchTest
static final ArchRule services_should_be_annotated = classes()
.that().resideInAPackage("..service..")
@@ -82,6 +101,16 @@ class ArchitectureTest {
.should().beAnnotatedWith(org.springframework.stereotype.Service.class)
.because("Classes named *Service should be registered as Spring @Service beans.");
// ===================================================================================
// 5. SHARED PACKAGE RULES
// ===================================================================================
@ArchTest
static final ArchRule shared_should_not_depend_on_domains = noClasses()
.that().resideInAPackage("auth_service.shared..")
.should().dependOnClassesThat().resideInAPackage("auth_service.domain..")
.because("Shared classes should be independent of specific domains.");
@ArchTest
static final ArchRule controllers_should_be_annotated = classes()
.that().resideInAPackage("..controller..")
@@ -1,10 +1,9 @@
package auth_service.configuration.security;
import auth_service.shared.test.AbstractUnitTest;
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;
@@ -12,8 +11,7 @@ import static org.mockito.Mockito.when;
/**
* Tests for JwtService.
*/
@ExtendWith(MockitoExtension.class)
class JwtServiceTest {
class JwtServiceTest extends AbstractUnitTest {
@Mock
private JwtConfig jwtConfig;
@@ -1,11 +1,11 @@
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 auth_service.shared.test.AbstractWebMvcTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
@@ -28,7 +28,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@WebMvcTest(LoginController.class)
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
@AutoConfigureJsonTesters
class LoginControllerTest {
class LoginControllerTest extends AbstractWebMvcTest {
@Autowired
private MockMvc mockMvc;
@@ -36,9 +36,6 @@ class LoginControllerTest {
@MockitoBean
private LoginService loginService;
@MockitoBean
private JwtService jwtService;
@MockitoBean
private JwtAuthenticationFilter jwtAuthenticationFilter; // Needed because it's used in SecurityConfig
@@ -49,9 +46,7 @@ class LoginControllerTest {
void login_Success() throws Exception {
// Arrange
var request = new LoginRequest("test@example.com", "password");
var authenticatedUser = User.builder().id(815L).email("test@example.com").build();
when(loginService.login(any(User.class))).thenReturn(authenticatedUser);
when(jwtService.generateToken("815", "test@example.com")).thenReturn("mock-token");
when(loginService.login(any(User.class))).thenReturn("mock-token");
// Act & Assert
mockMvc.perform(post("/api/auth/login")
@@ -0,0 +1,60 @@
package auth_service.domain.login.persistence;
import auth_service.domain.login.persistence.entities.MinimalUserEntity;
import auth_service.shared.test.AbstractPersistenceTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
import org.springframework.context.annotation.Import;
import static org.junit.jupiter.api.Assertions.*;
@Import(MinimalUserRepositoryImpl.class)
class MinimalUserRepositoryTest extends AbstractPersistenceTest {
@Autowired
private MinimalUserRepository minimalUserRepository;
@Autowired
private TestEntityManager entityManager;
@Test
void findByEmail_Success() {
// Arrange
var email = "minimal@example.com";
var entity = MinimalUserEntity.builder()
.email(email)
.password("password")
.enabled(true)
.build();
entityManager.persist(entity);
entityManager.flush();
// Act
var result = minimalUserRepository.findByEmail(email);
// Assert
assertTrue(result.isPresent());
assertEquals(email, result.get().getEmail());
}
@Test
void updateLoginDate_Success() {
// Arrange
var entity = MinimalUserEntity.builder()
.email("login@example.com")
.password("password")
.enabled(true)
.build();
entity = entityManager.persist(entity);
entityManager.flush();
// Act
minimalUserRepository.updateLoginDate(entity.getId());
entityManager.clear(); // Clear cache to force reload from DB
// Assert
var updated = entityManager.find(MinimalUserEntity.class, entity.getId());
assertNotNull(updated.getLastLoginDate());
}
}
@@ -4,12 +4,11 @@ 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 auth_service.shared.test.AbstractUnitTest;
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;
@@ -21,8 +20,7 @@ import static org.mockito.Mockito.when;
/**
* Tests for LoginService.
*/
@ExtendWith(MockitoExtension.class)
class LoginServiceTest {
class LoginServiceTest extends AbstractUnitTest {
@Mock
private MinimalUserRepository minimalUserRepository;
@@ -30,6 +28,9 @@ class LoginServiceTest {
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private TokenGenerator tokenGenerator;
@InjectMocks
private LoginService loginService;
@@ -47,17 +48,19 @@ class LoginServiceTest {
void login_Success() {
// Arrange
var dbUser = User.builder()
.id(815L)
.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);
when(tokenGenerator.generateToken("815", "test@example.com")).thenReturn("mock-token");
// Act
var result = loginService.login(user);
// Assert
assertEquals(dbUser, result);
assertEquals("mock-token", result);
}
@Test
@@ -6,6 +6,7 @@ import auth_service.domain.registration.controller.dto.request.RegistrationReque
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
import auth_service.domain.registration.model.Registration;
import auth_service.domain.registration.service.RegistrationService;
import auth_service.shared.test.AbstractWebMvcTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
@@ -28,7 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@WebMvcTest(RegistrationController.class)
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
@AutoConfigureJsonTesters
class RegistrationControllerTest {
class RegistrationControllerTest extends AbstractWebMvcTest {
@Autowired
private MockMvc mockMvc;
@@ -0,0 +1,78 @@
package auth_service.domain.registration.persistence;
import auth_service.domain.registration.model.Registration;
import auth_service.domain.registration.persistence.entities.RegisteredUserEntity;
import auth_service.shared.test.AbstractPersistenceTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
import org.springframework.context.annotation.Import;
import static org.junit.jupiter.api.Assertions.*;
@Import(RegisteredUserRepositoryImpl.class)
class RegisteredUserRepositoryTest extends AbstractPersistenceTest {
@Autowired
private RegisteredUserRepository registeredUserRepository;
@Autowired
private TestEntityManager entityManager;
@Test
void existsByEmail_Success() {
// Arrange
var email = "exists@example.com";
var entity = RegisteredUserEntity.builder()
.email(email)
.password("password")
.enabled(true)
.steamId(111L)
.registrationDate(java.time.LocalDateTime.now())
.build();
entityManager.persist(entity);
entityManager.flush();
// Act & Assert
assertTrue(registeredUserRepository.existsByEmail(email));
assertFalse(registeredUserRepository.existsByEmail("other@example.com"));
}
@Test
void existsBySteamId_Success() {
// Arrange
var steamId = 222L;
var entity = RegisteredUserEntity.builder()
.email("steam@example.com")
.password("password")
.enabled(true)
.steamId(steamId)
.registrationDate(java.time.LocalDateTime.now())
.build();
entityManager.persist(entity);
entityManager.flush();
// Act & Assert
assertTrue(registeredUserRepository.existsBySteamId(steamId));
assertFalse(registeredUserRepository.existsBySteamId(333L));
}
@Test
void save_Success() {
// Arrange
var registration = Registration.builder()
.email("save@example.com")
.encryptedPassword("hashed")
.steamId(444L)
.build();
// Act
long id = registeredUserRepository.save(registration);
// Assert
assertTrue(id > 0);
var saved = entityManager.find(RegisteredUserEntity.class, id);
assertNotNull(saved);
assertEquals("save@example.com", saved.getEmail());
}
}
@@ -5,12 +5,11 @@ import auth_service.domain.registration.exception.InvalidInvitationCodeException
import auth_service.domain.registration.exception.SteamIdAlreadyRegisteredException;
import auth_service.domain.registration.model.Registration;
import auth_service.domain.registration.persistence.RegisteredUserRepository;
import auth_service.shared.test.AbstractUnitTest;
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 static org.junit.jupiter.api.Assertions.assertEquals;
@@ -21,8 +20,7 @@ import static org.mockito.Mockito.*;
/**
* Tests for RegistrationService.
*/
@ExtendWith(MockitoExtension.class)
class RegistrationServiceTest {
class RegistrationServiceTest extends AbstractUnitTest {
@Mock
private CodeValidationService codeValidationService;
@@ -8,6 +8,7 @@ import auth_service.domain.user.exception.UserNotFoundException;
import auth_service.domain.user.model.User;
import auth_service.domain.user.model.UserSettings;
import auth_service.domain.user.service.UserService;
import auth_service.shared.test.AbstractWebMvcTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,7 +35,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@WebMvcTest(UserController.class)
@AutoConfigureMockMvc(addFilters = false)
@AutoConfigureJsonTesters
class UserControllerTest {
class UserControllerTest extends AbstractWebMvcTest {
@Autowired
private MockMvc mockMvc;
@@ -0,0 +1,75 @@
package auth_service.domain.user.persistence;
import auth_service.domain.user.model.UserSettings;
import auth_service.domain.user.persistence.entities.UserEntity;
import auth_service.shared.test.AbstractPersistenceTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
import org.springframework.context.annotation.Import;
import java.time.LocalDateTime;
import static org.junit.jupiter.api.Assertions.*;
@Import(UserRepositoryImpl.class)
class UserRepositoryTest extends AbstractPersistenceTest {
@Autowired
private UserRepository userRepository;
@Autowired
private TestEntityManager entityManager;
@Test
void findByEmail_Success() {
// Arrange
var email = "test@example.com";
var userEntity = UserEntity.builder()
.email(email)
.password("password")
.enabled(true)
.steamId(123456L)
.registrationDate(LocalDateTime.now())
.build();
entityManager.persist(userEntity);
entityManager.flush();
// Act
var result = userRepository.findByEmail(email);
// Assert
assertTrue(result.isPresent());
assertEquals(email, result.get().getEmail());
}
@Test
void updateSettings_Success() {
// Arrange
var email = "settings@example.com";
var userEntity = UserEntity.builder()
.email(email)
.password("password")
.enabled(true)
.steamId(123456L)
.registrationDate(LocalDateTime.now())
.build();
userEntity = entityManager.persist(userEntity);
entityManager.flush();
var settings = UserSettings.builder()
.language("de")
.theme("dark")
.build();
// Act
var updated = userRepository.updateSettings(userEntity.getId(), 654321L, settings);
// Assert
assertTrue(updated);
var updatedUser = entityManager.find(UserEntity.class, userEntity.getId());
assertEquals(654321L, updatedUser.getSteamId());
assertNotNull(updatedUser.getSettings());
assertEquals("de", updatedUser.getSettings().getLanguage());
}
}
@@ -4,11 +4,10 @@ import auth_service.domain.user.exception.UserNotFoundException;
import auth_service.domain.user.model.User;
import auth_service.domain.user.model.UserSettings;
import auth_service.domain.user.persistence.UserRepository;
import auth_service.shared.test.AbstractUnitTest;
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;
@@ -19,8 +18,7 @@ import static org.mockito.Mockito.*;
/**
* Tests for UserService.
*/
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
class UserServiceTest extends AbstractUnitTest {
@Mock
private UserRepository userRepository;
@@ -0,0 +1,10 @@
package auth_service.shared.test;
import org.junit.jupiter.api.Tag;
/**
* Base class for ArchUnit tests.
*/
@Tag("ArchitectureTest")
public abstract class AbstractArchitectureTest {
}
@@ -0,0 +1,22 @@
package auth_service.shared.test;
import org.junit.jupiter.api.Tag;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Base class for integration tests.
* Full Spring context with Testcontainers.
*/
@Tag("IntegrationTest")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
public abstract class AbstractIntegrationTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
}
@@ -0,0 +1,24 @@
package auth_service.shared.test;
import org.junit.jupiter.api.Tag;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Base class for persistence tests.
* Slices only the persistence layer with Testcontainers.
*/
@Tag("PersistenceTest")
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
public abstract class AbstractPersistenceTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
}
@@ -0,0 +1,14 @@
package auth_service.shared.test;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
/**
* Base class for unit tests.
* Isolated from Spring context.
*/
@Tag("UnitTest")
@ExtendWith(MockitoExtension.class)
public abstract class AbstractUnitTest {
}
@@ -0,0 +1,13 @@
package auth_service.shared.test;
import org.junit.jupiter.api.Tag;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
/**
* Base class for WebMvc tests.
* Slices the web layer.
*/
@Tag("WebMvcTest")
@WebMvcTest
public abstract class AbstractWebMvcTest {
}