Skip to content

Commit 0a07d89

Browse files
committed
Updated documentation and cleanup.
1 parent 7fe5eeb commit 0a07d89

File tree

2 files changed

+58
-86
lines changed

2 files changed

+58
-86
lines changed

README.md

Lines changed: 56 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
# Spring Local PostgreSQL
22

33
## Description
4-
Provides configuration of an embedded PostgreSQL database (via Testcontainers)
5-
within Spring Boot Applications for local development and testing.
4+
Provides enhanced configuration of an embedded PostgreSQL database provided by Testcontainers. For use within Spring Boot Applications to support local development in addition to integration test execution.
65

7-
Requires minimal configuration using Spring conventions, but a variety of optional properties are supported to override default behavior.
6+
Requires minimal configuration using Spring conventions, but a variety of optional properties are provided to override default behavior and control the underlying container's configuration by profile.
7+
8+
## Features
9+
- Configure whether the embedded PostgreSQL is active or not. Allows you to control its activation by profile.
10+
- Configure the Docker image to contain the embedded PostgreSQL. Allows you to match your local and test environments with the version of PostgreSQL running in production.
11+
- Configure the embedded PostgreSQL to run on a defined, fixed port. Useful for local development so that developers can connect to the database with their client of choice with consistent configuration.
12+
- Configure whether to follow the containers log output. Useful for troubleshooting.
13+
- Configure the database name to match production.
14+
- Configure a database super user to handle migration scripts and a second user with fewer privileges for the Application to use.
15+
- Configure an SQL script to run when the PostgreSQL database is spun up.
816

917
## Rationale
1018
When developing an Application that uses PostgreSQL in production, an embedded PostgreSQL server provides the benefits of using an in-memory database, like H2, but avoids the downsides. The database is spun up and torn down when the Application starts up and shuts down, but developers are able to utilize PostgreSQL features (that alternatives like H2 may not support) and the test and local environments better resemble production. Development is more effective and reliable.
1119

12-
While Testcontainers is meant to be used exclusively in support of integration tests, this module is designed to support running the Application locally as well, reducing the overhead of maintaining Testcontainers and some other solution that fundamentally does the same thing. There is no need to maintain a local PostgreSQL server nor additional Docker configuration inside or outside the project.
20+
While Testcontainers is meant to be used exclusively in support of integration tests, this project is designed to support running the Application locally as well, reducing the overhead of maintaining Testcontainers and some other solution that fundamentally does the same thing. There is no need to maintain a local PostgreSQL server nor additional Docker configuration inside or outside the project.
1321

1422
## Requirements
1523
### Java 17
@@ -19,7 +27,6 @@ https://adoptium.net/temurin/releases/?version=17
1927
https://www.docker.com/products/docker-desktop/
2028

2129
### PostgreSQL JDBC Driver
22-
https://jdbc.postgresql.org<br>
2330
```xml
2431
<dependency>
2532
<groupId>org.postgresql</groupId>
@@ -28,104 +35,68 @@ https://jdbc.postgresql.org<br>
2835
</dependency>
2936
```
3037

31-
### Testcontainers PostgreSQL
32-
Version `1.18.3` is included as a transitive dependency.<br>
33-
https://www.testcontainers.org/modules/databases/postgres
38+
### Spring Boot Starter JDBC
3439
```xml
3540
<dependency>
36-
<groupId>org.testcontainers</groupId>
37-
<artifactId>postgresql</artifactId>
38-
<version>1.18.3</version>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-starter-jdbc</artifactId>
3943
</dependency>
4044
```
4145

42-
### Spring Boot 3
43-
A variety of modules from version `3.1.2` are included as transitive dependencies.<br>
44-
https://spring.io/projects/spring-boot
45-
```xml
46-
<dependencyManagement>
47-
<dependencies>
48-
<dependency>
49-
<groupId>org.springframework.boot</groupId>
50-
<artifactId>spring-boot-dependencies</artifactId>
51-
<version>3.1.2</version>
52-
<type>pom</type>
53-
<scope>import</scope>
54-
</dependency>
55-
</dependencies>
56-
</dependencyManagement>
57-
```
58-
```xml
59-
<dependencies>
60-
<dependency>
61-
<groupId>org.springframework.boot</groupId>
62-
<artifactId>spring-boot-starter-web</artifactId>
63-
</dependency>
64-
<dependency>
65-
<groupId>org.springframework.boot</groupId>
66-
<artifactId>spring-boot-configuration-processor</artifactId>
67-
</dependency>
68-
</dependencies>>
69-
```
46+
## Dependencies
47+
- Spring Boot Starter Web 3.2.0
48+
- Spring Boot Configuration Processor 3.2.0
49+
- Spring Boot Starter Test 3.2.0
50+
- Spring Boot Testcontainers 3.2.0
51+
- Testcontainers PostgreSQL 1.19.3
52+
7053
## Usage
7154

72-
### Configuration
55+
### Configuration as a Test Dependency
56+
While it is possible to configure this project as a compile dependency, and control its activation with profiles, it is not good practice. This project should always be configured as a test dependency.
57+
58+
However, this means that all configuration of this project can only reside in your project's test source, which is fine for integration tests, but= what about running the Application locally?
59+
60+
To do this we implement an approach surfaced in this [article](https://bsideup.github.io/posts/local_development_with_testcontainers/) by Sergei Egorov.
7361

74-
First, add this module as a dependency in your project:
62+
First, Add this project's artifact to your project as a test dependency:
7563
```xml
7664
<dependency>
7765
<groupId>io.github.quinnandrews</groupId>
7866
<artifactId>spring-local-postgresql</artifactId>
7967
<version>1.0-SNAPSHOT</version>
68+
<scope>test</scope>
8069
</dependency>
8170
```
71+
(NOTE: This project's artifact is NOT yet available in Maven Central)
8272

83-
Next, add `@EnableLocalPostreSQL` to your Spring Boot Application Class:
84-
```java
85-
@EnableLocalPostgreSQL
86-
@SpringBootApplication
87-
public class Application {
88-
89-
public static void main(final String[] args) {
90-
SpringApplication.run(Application.class, args);
91-
}
92-
}
93-
```
94-
95-
Then define the following property for the profiles that should initialize the embedded PostgreSQL:
96-
```properties
97-
spring.local.postgresql.engaged=true
98-
```
99-
100-
If desired, define any of the following properties to override default behavior (see below for detailed descriptions):
73+
Next, create properties files in your the test resources directory for `local` and `test` profiles with your configuration of choice. We recommend that the `local` profile is configured with a fixed port while the `test` profile is configured to use a random port, which is considered best practice for integration tests. And you may want do things like enable following of the container logs for the `local` profile as well:
10174

75+
application-local.properties
10276
```properties
10377
spring.local.postgresql.container.image=postgres:15
10478
spring.local.postgresql.container.port=15432
10579
spring.local.postgresql.container.log.follow=true
106-
spring.local.postgresql.database.name=local
107-
spring.local.postgresql.database.username=superuser
108-
spring.local.postgresql.database.password=password
109-
spring.local.postgresql.database.application.username=appuser
110-
spring.local.postgresql.database.application.password=password
80+
spring.local.postgresql.database.name=pedals
81+
spring.local.postgresql.database.username=fuzz
82+
spring.local.postgresql.database.password=echo
83+
spring.local.postgresql.database.application.username=overdrive
84+
spring.local.postgresql.database.application.password=reverb
11185
spring.local.postgresql.database.init.script=data/init.sql
11286
```
11387

114-
### Configuration as a Test Dependency
115-
Understandably, one may prefer this module as a test dependency rather than a compile dependency. But this means that all configuration for this module can only reside in your project's test source, which is fine for integration tests, but how, then, can you run the Application locally?
116-
117-
To do this we implement an approach surfaced in this [article](https://bsideup.github.io/posts/local_development_with_testcontainers/) by Sergei Egorov.
118-
119-
First, add this module as a test dependency in your project:
120-
```xml
121-
<dependency>
122-
<groupId>io.github.quinnandrews</groupId>
123-
<artifactId>spring-local-postgresql</artifactId>
124-
<version>1.0-SNAPSHOT</version>
125-
<scope>test</scope>
126-
</dependency>
88+
application-test.properties
89+
```properties
90+
spring.local.postgresql.container.image=postgres:15
91+
spring.local.postgresql.database.name=pedals
92+
spring.local.postgresql.database.username=fuzz
93+
spring.local.postgresql.database.password=echo
94+
spring.local.postgresql.database.application.username=overdrive
95+
spring.local.postgresql.database.application.password=reverb
96+
spring.local.postgresql.database.init.script=data/init.sql
12797
```
128-
Next, add a Spring Boot Application Class to your project's test source that includes the `@EnableLocalPostgreSQL` Annotation and passes the Application Class in your project's main source to the `run` method (so that Configuration in the main source is initialized):
98+
99+
Then add a Spring Boot Application Class to your project's test source that includes the `@EnableLocalPostgreSQL` Annotation and passes the Application Class in your project's main source to the `run` method (so that Configuration in the main source is initialized):
129100
```java
130101
@EnableLocalPostgreSQL
131102
@SpringBootApplication
@@ -137,7 +108,7 @@ public class LocalDevApplication {
137108
}
138109
```
139110

140-
Then you can reference `LocalApplication.class` in your integration tests to enable the embedded PostgreSQL by using the `classes` attribute on `@SpringBootTest`:
111+
Now you can reference `LocalApplication.class` in your integration tests to enable the embedded PostgreSQL by using the `classes` attribute on `@SpringBootTest`:
141112
```java
142113
@ActiveProfiles("test")
143114
@SpringBootTest(classes = LocalApplication.class)
@@ -146,7 +117,7 @@ class IntegrationTest {
146117
}
147118
```
148119

149-
Or, alternatively, your integration tests can ignore `LocalApplication.class` and enable the embedded PostgreSQL by using `@EnableLocalPostgreSQL`:
120+
Or, alternatively, your integration tests can include the embedded PostgreSQL directly by using `@EnableLocalPostgreSQL` (NOTE: You may need to declare the Application Class in your main source using `classes` attribute to avoid conflicts):
150121
```java
151122
@EnableLocalPostgreSQL
152123
@ActiveProfiles("test")
@@ -155,13 +126,14 @@ class IntegrationTest {
155126

156127
}
157128
```
129+
158130
Then you can create a `Run Configuration` in IntelliJ IDEA, for example, setting `LocalApplication.class` as the `Main Class` and defining `local` as the active profile.
159131

160-
Now when you run the `Run Configuration` or your integration tests, the embedded PostgreSQL will be initialized, assuming that the `local` and `test` profiles have set the `spring.local.postgresql.engaged` property to `true'.`
132+
Now when you run the `Run Configuration` or your integration tests, the embedded PostgreSQL will be initialized.
161133

162-
**But there is a way to make this even more convenient.**
134+
**_But there is a way to make this even more convenient._**
163135

164-
If your integration tests reference `LocalApplication.class`, it's worth noting that the `main` method isn't actually executed in that case. Spring is doing something different.
136+
If your integration tests reference `LocalApplication.class`, it's worth noting that the `main` method isn't actually executed when the tests run. Spring is using the Class for reference and doing something different in place of executing the `main` method.
165137

166138
What this means is that you can activate the `local` profile explicitly in the body of the `main` method:
167139
```java
@@ -177,7 +149,7 @@ public class LocalApplication {
177149
}
178150
```
179151

180-
Now you can run the Application locally in IntelliJ IDEA by simply right-clicking on `LocalApplication.class` in the Project Panel and selecting `Run 'LocalApplication'` from the Context Menu, which will also create a `Run Configuration` for later use.
152+
Now you can run the Application locally in IntelliJ IDEA by simply right-clicking on `LocalApplication.class` in the Project Panel and selecting `Run 'LocalApplication'` from the Context Menu, which will also create a `Run Configuration` for later use, but you don't need to do make any changes to the `Run Configuration`. Its default setting work just fine.
181153

182154
### Supported Configuration Properties
183155

src/main/java/org/quinnandrews/spring/local/postgresql/config/PostgreSQLContainerConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ Use the credentials below to connect your client of choice (DBeaver,
155155
*/
156156
@Bean
157157
public JdbcConnectionDetails jdbcConnectionDetails(@Value("${spring.local.postgresql.database.application.username:#{null}}")
158-
final String applicationUsername,
158+
final String applicationUsername,
159159
@Value("${spring.local.postgresql.database.application.password:#{null}}")
160-
final String applicationPassword,
160+
final String applicationPassword,
161161
final PostgreSQLContainer<?> container) {
162162
return new LocalPostgreSQLConnectionDetails(applicationUsername, applicationPassword, container);
163163
}

0 commit comments

Comments
 (0)