-
Notifications
You must be signed in to change notification settings - Fork 26
Add TestContainers sample for Doma Spring Boot #310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
2a0f96f
448f356
5198bb1
1e42f72
06610a1
45661c4
87b5535
237ea2d
487094d
2a5fa14
ccf7bfc
ccbf51f
cf62c8e
5f6bdc4
5f5aa9a
37dc226
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # Doma Spring Boot Sample with TestContainers | ||
|
|
||
| This sample demonstrates how to use [TestContainers](https://www.testcontainers.org/) with Doma and Spring Boot. | ||
|
|
||
| ## Running the Sample | ||
|
|
||
| To run this sample, you need: | ||
| - Java 17 or later | ||
| - Maven | ||
| - Docker (for running TestContainers) | ||
|
|
||
| ### Build and Run Tests | ||
|
|
||
| ```bash | ||
| ./mvnw clean test | ||
| ``` | ||
|
|
||
| ### Run with TestContainers | ||
|
|
||
| ```bash | ||
| ./mvnw spring-boot:test-run | ||
| ``` | ||
|
|
||
| This will start the application with a PostgreSQL container. | ||
|
|
||
| ## Features Demonstrated | ||
|
|
||
| - Using TestContainers to start a PostgreSQL database for tests | ||
| - Spring Boot's native TestContainers integration with `@ServiceConnection` | ||
| - Using TestContainers at development time with `SpringApplication.from()` | ||
| - Running Doma queries against a real PostgreSQL database in tests | ||
| - Configuration for both development (H2) and test (PostgreSQL) environments | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <artifactId>doma-spring-boot-sample-testcontainers</artifactId> | ||
| <packaging>jar</packaging> | ||
|
|
||
| <name>doma-spring-boot-sample-testcontainers</name> | ||
| <description>Demo project for Spring Boot with Doma and TestContainers</description> | ||
|
|
||
| <parent> | ||
| <groupId>org.seasar.doma.boot</groupId> | ||
| <artifactId>doma-spring-boot-samples</artifactId> | ||
| <version>2.5.0-SNAPSHOT</version> | ||
| <relativePath>../pom.xml</relativePath> | ||
| </parent> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.seasar.doma</groupId> | ||
| <artifactId>doma-core</artifactId> | ||
| <version>${doma.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.seasar.doma</groupId> | ||
| <artifactId>doma-processor</artifactId> | ||
| <version>${doma.version}</version> | ||
| <optional>true</optional> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.seasar.doma.boot</groupId> | ||
| <artifactId>doma-spring-boot-starter</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-web</artifactId> | ||
| </dependency> | ||
| <!-- PostgreSQL Driver --> | ||
|
||
| <dependency> | ||
| <groupId>org.postgresql</groupId> | ||
| <artifactId>postgresql</artifactId> | ||
| <scope>runtime</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-test</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
|
||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <!-- Spring Boot manages TestContainers dependencies --> | ||
|
||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-testcontainers</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.testcontainers</groupId> | ||
| <artifactId>postgresql</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-maven-plugin</artifactId> | ||
| <version>${spring-boot.version}</version> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
|
||
| @SpringBootApplication | ||
| public class Application { | ||
|
|
||
| @SuppressWarnings("resource") | ||
| public static void main(String[] args) { | ||
| SpringApplication.run(Application.class, args); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import org.seasar.doma.*; | ||
|
|
||
| @Entity | ||
| @Table(name = "messages") | ||
| public class Message { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| public Integer id; | ||
|
|
||
| public String text; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.seasar.doma.boot.Pageables; | ||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.data.web.PageableDefault; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RequestParam; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/") | ||
|
||
| public class MessageController { | ||
|
|
||
| private final MessageDao messageDao; | ||
|
|
||
| public MessageController(MessageDao messageDao) { | ||
| this.messageDao = messageDao; | ||
| } | ||
|
|
||
| @GetMapping | ||
| List<Message> list(@PageableDefault Pageable pageable) { | ||
| return messageDao.selectAll(Pageables.toSelectOptions(pageable)); | ||
| } | ||
|
|
||
| @GetMapping(params = "text") | ||
| Message add(@RequestParam String text) { | ||
| Message message = new Message(); | ||
| message.text = text; | ||
| messageDao.insert(message); | ||
| return message; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.seasar.doma.Dao; | ||
| import org.seasar.doma.Insert; | ||
| import org.seasar.doma.Select; | ||
| import org.seasar.doma.boot.ConfigAutowireable; | ||
| import org.seasar.doma.jdbc.SelectOptions; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Dao | ||
| @ConfigAutowireable | ||
| @Transactional | ||
| public interface MessageDao { | ||
| @Select | ||
| List<Message> selectAll(SelectOptions options); | ||
|
|
||
| @Insert | ||
| int insert(Message message); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| SELECT id, text FROM messages ORDER BY id; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Development configuration using TestContainers | ||
|
||
| spring.sql.init.mode=always | ||
|
|
||
| # Doma configuration | ||
| doma.naming=SNAKE_LOWER_CASE | ||
| logging.level.org.springframework.jdbc.support.JdbcTransactionManager=DEBUG | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| CREATE TABLE IF NOT EXISTS messages ( | ||
| id SERIAL PRIMARY KEY, | ||
| text VARCHAR(255) | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| 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.test.context.SpringBootTest.WebEnvironment; | ||
| import org.springframework.boot.test.web.server.LocalServerPort; | ||
| import org.springframework.context.annotation.Import; | ||
| import org.springframework.core.ParameterizedTypeReference; | ||
| import org.springframework.web.client.RestClient; | ||
| import org.springframework.web.util.UriComponentsBuilder; | ||
|
|
||
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) | ||
| @Import(TestcontainersConfiguration.class) | ||
| class ApplicationTest { | ||
| private RestClient restClient; | ||
| private final ParameterizedTypeReference<List<Message>> typedReference = new ParameterizedTypeReference<List<Message>>() { | ||
|
||
| }; | ||
| @LocalServerPort | ||
| private int port; | ||
|
|
||
| @BeforeEach | ||
| void setUp(@Autowired RestClient.Builder restClientBuilder) { | ||
| this.restClient = restClientBuilder | ||
| .baseUrl("http://localhost:" + port) | ||
| .defaultStatusHandler(__ -> true, (req, res) -> { | ||
| }).build(); | ||
| } | ||
|
|
||
| @Test | ||
| void testWithTestContainers() { | ||
| Message message1 = restClient.get() | ||
| .uri("/?text={text}", "hello") | ||
| .retrieve() | ||
| .body(Message.class); | ||
| assertEquals(1, message1.id); | ||
| assertEquals("hello", message1.text); | ||
|
|
||
| Message message2 = restClient.get() | ||
| .uri("/?text={text}", "world") | ||
| .retrieve() | ||
| .body(Message.class); | ||
| assertEquals(2, message2.id); | ||
| assertEquals("world", message2.text); | ||
|
|
||
| { | ||
| List<Message> messages = restClient.get() | ||
| .uri("/") | ||
| .retrieve() | ||
| .body(typedReference); | ||
| assertEquals(2, messages.size()); | ||
| assertEquals(message1.id, messages.get(0).id); | ||
| assertEquals(message1.text, messages.get(0).text); | ||
| assertEquals(message2.id, messages.get(1).id); | ||
| assertEquals(message2.text, messages.get(1).text); | ||
| } | ||
|
|
||
| { | ||
| List<Message> messages = restClient.get() | ||
| .uri("/?page={page}&size={size}", 1, 1) | ||
| .retrieve() | ||
| .body(typedReference); | ||
| assertEquals(1, messages.size()); | ||
| assertEquals(message2.id, messages.get(0).id); | ||
| assertEquals(message2.text, messages.get(0).text); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| import org.springframework.boot.SpringApplication; | ||
|
|
||
| public class TestApplication { | ||
|
|
||
| public static void main(String[] args) { | ||
| SpringApplication.from(Application::main).with(TestcontainersConfiguration.class).run(args); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package org.seasar.doma.boot.sample; | ||
|
|
||
| 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.PostgreSQLContainer; | ||
| import org.testcontainers.utility.DockerImageName; | ||
|
|
||
| @TestConfiguration(proxyBeanMethods = false) | ||
| class TestcontainersConfiguration { | ||
|
|
||
| @Bean | ||
| @ServiceConnection | ||
| PostgreSQLContainer<?> postgresContainer() { | ||
| return new PostgreSQLContainer<>(DockerImageName.parse("postgres:latest")); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # Test configuration for PostgreSQL | ||
| spring.sql.init.mode=always | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add maven wrapper