diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index fa05c1061a..251dba0316 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -91,6 +91,7 @@ spring-boot-3-native spring-boot-3-observation spring-boot-3-test-pitfalls + spring-boot-3-testcontainers spring-boot-resilience4j spring-boot-properties spring-boot-properties-2 diff --git a/spring-boot-modules/spring-boot-3-testcontainers/README.md b/spring-boot-modules/spring-boot-3-testcontainers/README.md new file mode 100644 index 0000000000..5616cce48b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/README.md @@ -0,0 +1 @@ +## Relevant Articles diff --git a/spring-boot-modules/spring-boot-3-testcontainers/pom.xml b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml new file mode 100644 index 0000000000..173fb8795c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + spring-boot-3-testcontainers + 0.0.1-SNAPSHOT + spring-boot-3-testcontainers + Testcontainer Improvements in Spring Boot 3 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + org.springframework.boot + spring-boot-testcontainers + + + + org.testcontainers + mongodb + ${testcontainers.version} + test + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + + + + io.rest-assured + rest-assured + ${rest-assured.version} + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 3.0.0-M7 + 1.18.3 + 5.3.1 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java new file mode 100644 index 0000000000..9a00bfebf2 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java new file mode 100644 index 0000000000..4780a2f66a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java @@ -0,0 +1,13 @@ +package com.baeldung.testcontainers.support; + +import java.util.UUID; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document("characters") +public record MiddleEarthCharacter(@Id String id, String name, String race) { + public MiddleEarthCharacter(String name, String race) { + this(UUID.randomUUID().toString(), name, race); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java new file mode 100644 index 0000000000..3b7bfddbef --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java @@ -0,0 +1,30 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("characters") +public class MiddleEarthCharactersController { + private final MiddleEarthCharactersRepository repository; + + public MiddleEarthCharactersController(MiddleEarthCharactersRepository repository) { + this.repository = repository; + } + + @GetMapping + public List findByRace(@RequestParam String race) { + return repository.findAllByRace(race); + } + + @PostMapping + public MiddleEarthCharacter save(@RequestBody MiddleEarthCharacter character) { + return repository.save(character); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java new file mode 100644 index 0000000000..a668650670 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MiddleEarthCharactersRepository extends MongoRepository { + List findAllByRace(String race); +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java new file mode 100644 index 0000000000..8689b10110 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java @@ -0,0 +1,59 @@ +package com.baeldung.testcontainers; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +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.test.annotation.DirtiesContext; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +class DynamicPropertiesIntegrationTest { + @Container + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizzard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java new file mode 100644 index 0000000000..a94c0f772a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java @@ -0,0 +1,29 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.devtools.restart.RestartScope; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +class LocalDevApplication { + + public static void main(String[] args) { + SpringApplication.from(Application::main) + .with(LocalDevTestcontainersConfig.class) + .run(args); + } + + @TestConfiguration(proxyBeanMethods = false) + static class LocalDevTestcontainersConfig { + @Bean + @RestartScope + @ServiceConnection + public MongoDBContainer mongoDBContainer() { + return new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + } + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java new file mode 100644 index 0000000000..500d6d2e61 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java @@ -0,0 +1,55 @@ +package com.baeldung.testcontainers; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +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.testcontainers.service.connection.ServiceConnection; +import org.springframework.test.annotation.DirtiesContext; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +class ServiceConnectionIntegrationTest { + + @Container + @ServiceConnection + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizzard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +}