From a0b97886df379f56c99d8501ed6f49c2892a2f10 Mon Sep 17 00:00:00 2001 From: igorsatsyuk Date: Mon, 25 May 2026 16:30:27 +0300 Subject: [PATCH] refactor(tests): unify constructor injection and remove @Autowired field usage --- .../integrationtest/AccountIntegrationIT.java | 22 +++++++++++----- .../api/integrationtest/AuthValidationIT.java | 10 +++++++ .../integrationtest/ClientIntegrationIT.java | 26 ++++++++++++++----- .../integrationtest/DpopIntegrationIT.java | 16 +++++++++--- .../KeycloakIntegrationIT.java | 10 +++++++ .../integrationtest/KeycloakNegativeIT.java | 10 +++++++ .../api/integrationtest/RateLimitingIT.java | 10 +++++++ .../api/util/AbstractIntegrationTest.java | 20 +++++++++----- .../api/util/KeycloakIntegrationTest.java | 9 +++++++ .../api/util/WireMockIntegrationTest.java | 9 +++++++ .../observability/LoggingCorrelationTest.java | 10 ++++--- 11 files changed, 126 insertions(+), 26 deletions(-) diff --git a/src/test/java/lt/satsyuk/api/integrationtest/AccountIntegrationIT.java b/src/test/java/lt/satsyuk/api/integrationtest/AccountIntegrationIT.java index 69ce9f4..aa39d54 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/AccountIntegrationIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/AccountIntegrationIT.java @@ -11,10 +11,13 @@ import lt.satsyuk.repository.ClientRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import lt.satsyuk.config.KeycloakProperties; +import lt.satsyuk.security.RateLimitingFilter; import java.math.BigDecimal; @@ -26,11 +29,18 @@ ) class AccountIntegrationIT extends KeycloakIntegrationTest { - @Autowired - private AccountRepository accountRepository; - - @Autowired - private ClientRepository clientRepository; + private final AccountRepository accountRepository; + private final ClientRepository clientRepository; + + AccountIntegrationIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter, + AccountRepository accountRepository, + ClientRepository clientRepository) { + super(props, cacheManager, rateLimitingFilter); + this.accountRepository = accountRepository; + this.clientRepository = clientRepository; + } @BeforeEach void setUp() { diff --git a/src/test/java/lt/satsyuk/api/integrationtest/AuthValidationIT.java b/src/test/java/lt/satsyuk/api/integrationtest/AuthValidationIT.java index 96c24f2..1040908 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/AuthValidationIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/AuthValidationIT.java @@ -3,16 +3,26 @@ import lt.satsyuk.MainApplication; import lt.satsyuk.dto.AppResponse; import lt.satsyuk.api.util.AbstractIntegrationTest; +import lt.satsyuk.config.KeycloakProperties; import lt.satsyuk.dto.KeycloakTokenResponse; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.*; +import lt.satsyuk.security.RateLimitingFilter; import java.util.Set; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MainApplication.class) class AuthValidationIT extends AbstractIntegrationTest { + AuthValidationIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + @Test void login_emptyFields_badRequest() { ResponseEntity> response = loginRequest( diff --git a/src/test/java/lt/satsyuk/api/integrationtest/ClientIntegrationIT.java b/src/test/java/lt/satsyuk/api/integrationtest/ClientIntegrationIT.java index 02b44b0..573e847 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/ClientIntegrationIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/ClientIntegrationIT.java @@ -17,9 +17,12 @@ import lt.satsyuk.service.ClientService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.*; +import lt.satsyuk.config.KeycloakProperties; +import lt.satsyuk.security.RateLimitingFilter; import java.util.Set; import java.util.UUID; @@ -39,12 +42,21 @@ class ClientIntegrationIT extends KeycloakIntegrationTest { public static final String ALICE = "Alice"; public static final String SMITH = "Smith"; public static final String PHONE = "+37061234567"; - @Autowired - ClientRepository repo; - @Autowired - AccountRepository accountRepository; - @Autowired - RequestRepository requestRepository; + private final ClientRepository repo; + private final AccountRepository accountRepository; + private final RequestRepository requestRepository; + + ClientIntegrationIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter, + ClientRepository repo, + AccountRepository accountRepository, + RequestRepository requestRepository) { + super(props, cacheManager, rateLimitingFilter); + this.repo = repo; + this.accountRepository = accountRepository; + this.requestRepository = requestRepository; + } @BeforeEach void setUp() { diff --git a/src/test/java/lt/satsyuk/api/integrationtest/DpopIntegrationIT.java b/src/test/java/lt/satsyuk/api/integrationtest/DpopIntegrationIT.java index 6d54dea..e0fd996 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/DpopIntegrationIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/DpopIntegrationIT.java @@ -14,11 +14,14 @@ import lt.satsyuk.model.Client; import lt.satsyuk.repository.ClientRepository; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.cache.CacheManager; +import lt.satsyuk.config.KeycloakProperties; +import lt.satsyuk.security.RateLimitingFilter; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -38,8 +41,15 @@ ) class DpopIntegrationIT extends WireMockIntegrationTest { - @Autowired - private ClientRepository clientRepository; + private final ClientRepository clientRepository; + + DpopIntegrationIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter, + ClientRepository clientRepository) { + super(props, cacheManager, rateLimitingFilter); + this.clientRepository = clientRepository; + } @Test void login_forwardsDpopHeaderToKeycloak() { diff --git a/src/test/java/lt/satsyuk/api/integrationtest/KeycloakIntegrationIT.java b/src/test/java/lt/satsyuk/api/integrationtest/KeycloakIntegrationIT.java index d98684b..3085841 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/KeycloakIntegrationIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/KeycloakIntegrationIT.java @@ -3,10 +3,14 @@ import lt.satsyuk.MainApplication; import lt.satsyuk.dto.AppResponse; import lt.satsyuk.api.util.KeycloakIntegrationTest; +import lt.satsyuk.config.KeycloakProperties; import lt.satsyuk.dto.KeycloakTokenResponse; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.*; +import lt.satsyuk.security.RateLimitingFilter; import static org.assertj.core.api.Assertions.assertThat; @@ -16,6 +20,12 @@ ) class KeycloakIntegrationIT extends KeycloakIntegrationTest { + KeycloakIntegrationIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + // ------------------------------------------------------------ // LOGIN TESTS // ------------------------------------------------------------ diff --git a/src/test/java/lt/satsyuk/api/integrationtest/KeycloakNegativeIT.java b/src/test/java/lt/satsyuk/api/integrationtest/KeycloakNegativeIT.java index 35309aa..0272fc7 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/KeycloakNegativeIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/KeycloakNegativeIT.java @@ -3,10 +3,14 @@ import lt.satsyuk.MainApplication; import lt.satsyuk.dto.AppResponse; import lt.satsyuk.api.util.WireMockIntegrationTest; +import lt.satsyuk.config.KeycloakProperties; import lt.satsyuk.dto.KeycloakTokenResponse; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.*; +import lt.satsyuk.security.RateLimitingFilter; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.springframework.http.HttpHeaders.CONTENT_TYPE; @@ -18,6 +22,12 @@ ) class KeycloakNegativeIT extends WireMockIntegrationTest { + KeycloakNegativeIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + // ------------------------------------------------------------ // KEYCLOAK CONNECTION FAILURES // ------------------------------------------------------------ diff --git a/src/test/java/lt/satsyuk/api/integrationtest/RateLimitingIT.java b/src/test/java/lt/satsyuk/api/integrationtest/RateLimitingIT.java index 42d2266..797c481 100644 --- a/src/test/java/lt/satsyuk/api/integrationtest/RateLimitingIT.java +++ b/src/test/java/lt/satsyuk/api/integrationtest/RateLimitingIT.java @@ -3,10 +3,14 @@ import lt.satsyuk.MainApplication; import lt.satsyuk.dto.AppResponse; import lt.satsyuk.api.util.WireMockIntegrationTest; +import lt.satsyuk.config.KeycloakProperties; import lt.satsyuk.dto.KeycloakTokenResponse; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; import org.springframework.http.*; +import lt.satsyuk.security.RateLimitingFilter; import java.util.ArrayList; import java.util.List; @@ -22,6 +26,12 @@ ) class RateLimitingIT extends WireMockIntegrationTest { + RateLimitingIT(@Qualifier("keycloakProperties") KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + // ------------------------------------------------------------ // LOGIN RATE LIMIT TESTS (5 requests per minute) // ------------------------------------------------------------ diff --git a/src/test/java/lt/satsyuk/api/util/AbstractIntegrationTest.java b/src/test/java/lt/satsyuk/api/util/AbstractIntegrationTest.java index f3b9fed..03b8b6d 100644 --- a/src/test/java/lt/satsyuk/api/util/AbstractIntegrationTest.java +++ b/src/test/java/lt/satsyuk/api/util/AbstractIntegrationTest.java @@ -15,9 +15,9 @@ import org.junit.jupiter.api.BeforeEach; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.TestConstructor; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.boot.test.web.server.LocalServerPort; @@ -40,6 +40,7 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @ActiveProfiles("test") @Testcontainers +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) public abstract class AbstractIntegrationTest { // Testcontainers-managed shared containers for integration tests @@ -82,16 +83,21 @@ static void checkDocker() { assumeTrue(pg != null && pg.isRunning(), "Postgres container must be running"); } - @Autowired - protected KeycloakProperties props; + protected final KeycloakProperties props; protected RestTemplate restTemplate; - @Autowired - protected CacheManager cacheManager; + protected final CacheManager cacheManager; - @Autowired - protected RateLimitingFilter rateLimitingFilter; + protected final RateLimitingFilter rateLimitingFilter; + + protected AbstractIntegrationTest(KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + this.props = props; + this.cacheManager = cacheManager; + this.rateLimitingFilter = rateLimitingFilter; + } // Use a local ObjectMapper in Boot 4 PoC so integration tests do not depend on a Spring-managed bean. protected final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); diff --git a/src/test/java/lt/satsyuk/api/util/KeycloakIntegrationTest.java b/src/test/java/lt/satsyuk/api/util/KeycloakIntegrationTest.java index fa055d7..10f5107 100644 --- a/src/test/java/lt/satsyuk/api/util/KeycloakIntegrationTest.java +++ b/src/test/java/lt/satsyuk/api/util/KeycloakIntegrationTest.java @@ -1,7 +1,10 @@ package lt.satsyuk.api.util; import dasniko.testcontainers.keycloak.KeycloakContainer; +import lt.satsyuk.config.KeycloakProperties; +import lt.satsyuk.security.RateLimitingFilter; import org.junit.jupiter.api.BeforeAll; +import org.springframework.cache.CacheManager; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.testcontainers.junit.jupiter.Container; @@ -10,6 +13,12 @@ public abstract class KeycloakIntegrationTest extends AbstractIntegrationTest { + protected KeycloakIntegrationTest(KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + @Container protected static KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.0.0") .withRealmImportFile("keycloak/realm-export.json") diff --git a/src/test/java/lt/satsyuk/api/util/WireMockIntegrationTest.java b/src/test/java/lt/satsyuk/api/util/WireMockIntegrationTest.java index c8ef0c7..1bd7d07 100644 --- a/src/test/java/lt/satsyuk/api/util/WireMockIntegrationTest.java +++ b/src/test/java/lt/satsyuk/api/util/WireMockIntegrationTest.java @@ -11,9 +11,12 @@ import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; +import lt.satsyuk.config.KeycloakProperties; +import lt.satsyuk.security.RateLimitingFilter; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.springframework.cache.CacheManager; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.annotation.DirtiesContext; @@ -33,6 +36,12 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class WireMockIntegrationTest extends AbstractIntegrationTest { + protected WireMockIntegrationTest(KeycloakProperties props, + CacheManager cacheManager, + RateLimitingFilter rateLimitingFilter) { + super(props, cacheManager, rateLimitingFilter); + } + protected static final String REALMS_PROTOCOL_OPENID_CONNECT_TOKEN = "/realms/.*/protocol/openid-connect/token"; protected static final String REALMS_PROTOCOL_OPENID_CONNECT_LOGOUT = "/realms/.*/protocol/openid-connect/logout"; protected static final String REALMS_PROTOCOL_OPENID_CONNECT_INTROSPECT = "/realms/.*/protocol/openid-connect/token/introspect"; diff --git a/src/test/java/lt/satsyuk/observability/LoggingCorrelationTest.java b/src/test/java/lt/satsyuk/observability/LoggingCorrelationTest.java index ccb57fb..ab5e821 100644 --- a/src/test/java/lt/satsyuk/observability/LoggingCorrelationTest.java +++ b/src/test/java/lt/satsyuk/observability/LoggingCorrelationTest.java @@ -6,12 +6,12 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.test.context.TestConstructor; import static org.assertj.core.api.Assertions.assertThat; @@ -28,12 +28,16 @@ } ) @ExtendWith(OutputCaptureExtension.class) +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) class LoggingCorrelationTest { private static final Logger log = LoggerFactory.getLogger(LoggingCorrelationTest.class); - @Autowired - private Tracer tracer; + private final Tracer tracer; + + LoggingCorrelationTest(Tracer tracer) { + this.tracer = tracer; + } @Test void logLineContainsTraceIdAndSpanIdWhenSpanIsActive(CapturedOutput output) {