diff --git a/backend/audit-writer-service/src/test/java/lt/satsyuk/distributed/audit/auditwriter/consumer/AuditEventConsumerKafkaTestcontainersTest.java b/backend/audit-writer-service/src/test/java/lt/satsyuk/distributed/audit/auditwriter/consumer/AuditEventConsumerKafkaTestcontainersTest.java index 433385f..ba17921 100644 --- a/backend/audit-writer-service/src/test/java/lt/satsyuk/distributed/audit/auditwriter/consumer/AuditEventConsumerKafkaTestcontainersTest.java +++ b/backend/audit-writer-service/src/test/java/lt/satsyuk/distributed/audit/auditwriter/consumer/AuditEventConsumerKafkaTestcontainersTest.java @@ -14,7 +14,6 @@ import org.awaitility.Awaitility; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.kafka.config.KafkaListenerEndpointRegistry; import org.springframework.kafka.core.DefaultKafkaProducerFactory; @@ -23,6 +22,7 @@ import org.springframework.kafka.test.utils.ContainerTestUtils; import org.springframework.kafka.test.utils.KafkaTestUtils; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -66,6 +66,7 @@ * of the module test suite. */ @Testcontainers(disabledWithoutDocker = true) +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @SpringBootTest( classes = AuditWriterServiceApplication.class, properties = { @@ -113,13 +114,17 @@ static void overrideProperties(DynamicPropertyRegistry registry) { @MockitoBean private BlockchainWriterService blockchainWriterService; + private final KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + + AuditEventConsumerKafkaTestcontainersTest(KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry) { + this.kafkaListenerEndpointRegistry = kafkaListenerEndpointRegistry; + } + @BeforeEach void resetMock() { reset(blockchainWriterService); } - @Autowired - private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; // ------------------------------------------------------------------------- // Helpers diff --git a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/AuthControllerWebFluxTest.java b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/AuthControllerWebFluxTest.java index 46d20a5..7085337 100644 --- a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/AuthControllerWebFluxTest.java +++ b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/AuthControllerWebFluxTest.java @@ -5,11 +5,11 @@ import lt.satsyuk.distributed.audit.contracts.auth.AuthTokenResponse; import lt.satsyuk.distributed.audit.contracts.auth.UserRole; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.webflux.test.autoconfigure.WebFluxTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; @@ -22,11 +22,15 @@ @WebFluxTest(controllers = AuthController.class) @Import(GlobalExceptionHandler.class) +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @WithMockUser class AuthControllerWebFluxTest { - @Autowired - private WebTestClient webTestClient; + private final WebTestClient webTestClient; + + AuthControllerWebFluxTest(WebTestClient webTestClient) { + this.webTestClient = webTestClient; + } @MockitoBean private AuthenticationService authenticationService; diff --git a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/CommandControllerWebFluxValidationTest.java b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/CommandControllerWebFluxValidationTest.java index 968081a..edef053 100644 --- a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/CommandControllerWebFluxValidationTest.java +++ b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/api/CommandControllerWebFluxValidationTest.java @@ -5,11 +5,11 @@ import lt.satsyuk.distributed.audit.command.service.UserLoginCommandService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.webflux.test.autoconfigure.WebFluxTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; @@ -20,11 +20,15 @@ @WebFluxTest(controllers = CommandController.class) @Import(GlobalExceptionHandler.class) +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @WithMockUser(roles = {"USER"}) class CommandControllerWebFluxValidationTest { - @Autowired - private WebTestClient webTestClient; + private final WebTestClient webTestClient; + + CommandControllerWebFluxValidationTest(WebTestClient webTestClient) { + this.webTestClient = webTestClient; + } @MockitoBean private UserLoginCommandService userLoginCommandService; diff --git a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/config/KafkaProducerConfigIntegrationTest.java b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/config/KafkaProducerConfigIntegrationTest.java index 3dae6f6..53aad28 100644 --- a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/config/KafkaProducerConfigIntegrationTest.java +++ b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/config/KafkaProducerConfigIntegrationTest.java @@ -6,11 +6,11 @@ import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestPropertySource; import java.util.Map; @@ -23,6 +23,7 @@ * is wired successfully from the real application context. */ @CommandServiceIntegrationTest +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @TestPropertySource(properties = { "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}", "spring.kafka.properties.client.id=command-service-it", @@ -33,17 +34,20 @@ class KafkaProducerConfigIntegrationTest { private static final String JSON_SERIALIZER_FQCN = "org.springframework.kafka.support.serializer.JsonSerializer"; - @Autowired - private KafkaTemplate auditEventKafkaTemplate; - - @Autowired - private ProducerFactory auditEventProducerFactory; - - @Autowired - private AuditCommandPublisher auditCommandPublisher; - - @Value("${spring.embedded.kafka.brokers}") - private String embeddedKafkaBrokers; + private final KafkaTemplate auditEventKafkaTemplate; + private final ProducerFactory auditEventProducerFactory; + private final AuditCommandPublisher auditCommandPublisher; + private final String embeddedKafkaBrokers; + + KafkaProducerConfigIntegrationTest(KafkaTemplate auditEventKafkaTemplate, + ProducerFactory auditEventProducerFactory, + AuditCommandPublisher auditCommandPublisher, + @Value("${spring.embedded.kafka.brokers}") String embeddedKafkaBrokers) { + this.auditEventKafkaTemplate = auditEventKafkaTemplate; + this.auditEventProducerFactory = auditEventProducerFactory; + this.auditCommandPublisher = auditCommandPublisher; + this.embeddedKafkaBrokers = embeddedKafkaBrokers; + } @Test void auditEventKafkaTemplateBeanIsCreated() { diff --git a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/service/UserLoginCommandServiceKafkaIntegrationTest.java b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/service/UserLoginCommandServiceKafkaIntegrationTest.java index ca5eea5..5800bf4 100644 --- a/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/service/UserLoginCommandServiceKafkaIntegrationTest.java +++ b/backend/command-service/src/test/java/lt/satsyuk/distributed/audit/command/service/UserLoginCommandServiceKafkaIntegrationTest.java @@ -17,7 +17,6 @@ import org.junit.jupiter.api.Assertions; 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.Value; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; @@ -27,6 +26,7 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; import org.springframework.kafka.test.utils.KafkaTestUtils; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestPropertySource; import org.springframework.context.annotation.Import; @@ -36,6 +36,7 @@ import java.util.UUID; @CommandServiceIntegrationTest +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @TestPropertySource(properties = { "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}" }) @@ -44,11 +45,14 @@ class UserLoginCommandServiceKafkaIntegrationTest { private static final String TOPIC = "user.login.events"; - @Autowired - private UserLoginCommandService userLoginCommandService; + private final UserLoginCommandService userLoginCommandService; + private final org.springframework.kafka.test.EmbeddedKafkaBroker embeddedKafkaBroker; - @Autowired - private org.springframework.kafka.test.EmbeddedKafkaBroker embeddedKafkaBroker; + UserLoginCommandServiceKafkaIntegrationTest(UserLoginCommandService userLoginCommandService, + org.springframework.kafka.test.EmbeddedKafkaBroker embeddedKafkaBroker) { + this.userLoginCommandService = userLoginCommandService; + this.embeddedKafkaBroker = embeddedKafkaBroker; + } private Consumer consumer; diff --git a/backend/event-store-service/src/test/java/lt/satsyuk/distributed/audit/eventstore/EventStoreKafkaToPostgresIntegrationTest.java b/backend/event-store-service/src/test/java/lt/satsyuk/distributed/audit/eventstore/EventStoreKafkaToPostgresIntegrationTest.java index 034635f..bc67c22 100644 --- a/backend/event-store-service/src/test/java/lt/satsyuk/distributed/audit/eventstore/EventStoreKafkaToPostgresIntegrationTest.java +++ b/backend/event-store-service/src/test/java/lt/satsyuk/distributed/audit/eventstore/EventStoreKafkaToPostgresIntegrationTest.java @@ -9,13 +9,13 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.testcontainers.containers.PostgreSQLContainer; @@ -42,6 +42,7 @@ import reactor.core.publisher.Mono; @SpringBootTest +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @Testcontainers(disabledWithoutDocker = true) @SuppressWarnings({"SqlNoDataSourceInspection", "SqlResolve"}) class EventStoreKafkaToPostgresIntegrationTest { @@ -102,11 +103,14 @@ event_hash VARCHAR(64), } } - @Autowired - private KafkaTemplate kafkaTemplate; + private final KafkaTemplate kafkaTemplate; + private final ObjectMapper objectMapper; - @Autowired - private ObjectMapper objectMapper; + EventStoreKafkaToPostgresIntegrationTest(KafkaTemplate kafkaTemplate, + ObjectMapper objectMapper) { + this.kafkaTemplate = kafkaTemplate; + this.objectMapper = objectMapper; + } @Test void userLoginEventIsPersistedToPostgresFromKafkaTopic() throws Exception { diff --git a/backend/query-service/src/main/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJob.java b/backend/query-service/src/main/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJob.java index 2120bf6..e591ba2 100644 --- a/backend/query-service/src/main/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJob.java +++ b/backend/query-service/src/main/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJob.java @@ -26,13 +26,7 @@ public class ReconciliationQuartzJob extends QuartzJobBean { private ReconciliationProperties reconciliationProperties; public ReconciliationQuartzJob() { - } - - @Autowired - public ReconciliationQuartzJob(ReconciliationReportService reconciliationReportService, - ReconciliationProperties reconciliationProperties) { - this.reconciliationReportService = reconciliationReportService; - this.reconciliationProperties = reconciliationProperties; + // Required for Quartz instantiation paths that construct the job reflectively. } @Autowired diff --git a/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/integration/IntegrityCheckIntegrationTest.java b/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/integration/IntegrityCheckIntegrationTest.java index e882d1d..1fc8518 100644 --- a/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/integration/IntegrityCheckIntegrationTest.java +++ b/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/integration/IntegrityCheckIntegrationTest.java @@ -7,11 +7,11 @@ import lt.satsyuk.distributed.audit.query.blockchain.AuditLedgerBlockchainClient; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpHeaders; import org.springframework.r2dbc.core.DatabaseClient; +import org.springframework.test.context.TestConstructor; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -38,13 +38,13 @@ * codes for the various blockchain response/error scenarios. */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) @Testcontainers class IntegrityCheckIntegrationTest { /** Valid 64-char hex hash used across multiple test cases. */ private static final String HASH_64 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; - @Autowired - JwtService jwtService; + private final JwtService jwtService; @SuppressWarnings("resource") @Container @@ -71,14 +71,18 @@ static void r2dbcProperties(DynamicPropertyRegistry registry) { @MockitoBean AuditLedgerBlockchainClient blockchainClient; - @Autowired - DatabaseClient databaseClient; + private final DatabaseClient databaseClient; @LocalServerPort int port; WebTestClient webTestClient; + IntegrityCheckIntegrationTest(JwtService jwtService, DatabaseClient databaseClient) { + this.jwtService = jwtService; + this.databaseClient = databaseClient; + } + @BeforeEach void setUp() { webTestClient = WebTestClient.bindToServer() diff --git a/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJobTest.java b/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJobTest.java index d9be942..a26ad72 100644 --- a/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJobTest.java +++ b/backend/query-service/src/test/java/lt/satsyuk/distributed/audit/query/jobs/ReconciliationQuartzJobTest.java @@ -37,7 +37,8 @@ private ReconciliationProperties reconciliationProperties() { @Test void executeInternalRunsScheduledReconciliation() { - ReconciliationQuartzJob job = new ReconciliationQuartzJob(reconciliationReportService, reconciliationProperties()); + ReconciliationQuartzJob job = new ReconciliationQuartzJob(); + job.setDependencies(reconciliationReportService, reconciliationProperties()); when(reconciliationReportService.runScheduled()).thenReturn(Mono.just(new ReconciliationReportResponse( "SCHEDULED", Instant.parse("2026-05-24T10:00:00Z"), @@ -55,7 +56,8 @@ void executeInternalRunsScheduledReconciliation() { @Test void executeInternalAllowsEmptyScheduledResponse() { - ReconciliationQuartzJob job = new ReconciliationQuartzJob(reconciliationReportService, reconciliationProperties()); + ReconciliationQuartzJob job = new ReconciliationQuartzJob(); + job.setDependencies(reconciliationReportService, reconciliationProperties()); when(reconciliationReportService.runScheduled()).thenReturn(Mono.empty()); assertDoesNotThrow(() -> job.executeInternal(jobExecutionContext)); @@ -64,7 +66,8 @@ void executeInternalAllowsEmptyScheduledResponse() { @Test void executeInternalWrapsRuntimeExceptionIntoJobExecutionException() { - ReconciliationQuartzJob job = new ReconciliationQuartzJob(reconciliationReportService, reconciliationProperties()); + ReconciliationQuartzJob job = new ReconciliationQuartzJob(); + job.setDependencies(reconciliationReportService, reconciliationProperties()); when(reconciliationReportService.runScheduled()).thenReturn(Mono.error(new IllegalStateException("boom"))); assertThrows(JobExecutionException.class, () -> job.executeInternal(jobExecutionContext)); @@ -73,7 +76,8 @@ void executeInternalWrapsRuntimeExceptionIntoJobExecutionException() { @Test void executeInternalSkipsWhenRunAlreadyInProgress() { - ReconciliationQuartzJob job = new ReconciliationQuartzJob(reconciliationReportService, reconciliationProperties()); + ReconciliationQuartzJob job = new ReconciliationQuartzJob(); + job.setDependencies(reconciliationReportService, reconciliationProperties()); when(reconciliationReportService.runScheduled()).thenReturn(Mono.error(new ReconciliationAlreadyRunningException())); assertDoesNotThrow(() -> job.executeInternal(jobExecutionContext));