Skip to content

Commit 145ccd7

Browse files
feat: Use Testcontainers for controller tests (#38)
[Testcontainers](https://github.com/testcontainers) allow us to spin up a temporary Docker image during tests. For this project, we will spin up a temporary PostgreSQL database to run the controller tests against a real PostgreSQL database instead of an in-memory H2 database. There are differences between PostgreSQL and H2 databases so if you plan to use a PostgreSQL database in production, it also makes sense to mimic this by using a PostgreSQL database in the tests. H2 databases are useful for quickly testing and running the system locally, but it is better to use Testcontainers to run a real PostgreSQL database for the controller tests. Use Testcontainers for controller tests: - Add `Testcontainers` annotation in controller tests. - Define a `PostgreSQLContainer` which will be used for the tests. - Add `application-postgres.yml` with connection settings for PostgreSQL. - Add `ActiveProfiles("postgres")` annotation in controller test which ensures it uses `application-postgres.yml`. - Update `README.md`.
1 parent 6cf0b90 commit 145ccd7

File tree

5 files changed

+63
-0
lines changed

5 files changed

+63
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,17 @@ and http://localhost:8081/ to view the Swagger documentation for each service.
151151
- [Liquibase](https://github.com/liquibase/liquibase) - Used to manage database schema changelogs
152152
- [WireMock](https://github.com/wiremock/wiremock) - For mocking HTTP services in tests
153153
- [Lombok](https://github.com/projectlombok/lombok) - Used to reduce boilerplate code
154+
- [Testcontainers](https://github.com/testcontainers) - Creates a temporary PostgreSQL database for tests
155+
156+
## Testing
157+
You can run the tests for this project using the following command:
158+
```
159+
./gradlew test
160+
```
161+
Please note that this project uses
162+
[Testcontainers](https://github.com/testcontainers)
163+
to create a temporary PostgreSQL database for tests. This requires
164+
a local Docker instance to be running when executing the tests.
154165

155166
## Gradle best practices for Kotlin
156167
[docs.gradle.org](https://docs.gradle.org/current/userguide/performance.html) - [kotlinlang.org](https://kotlinlang.org/docs/gradle-best-practices.html)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
spring:
2+
datasource:
3+
url: jdbc:postgresql://localhost:5432/sample-db
4+
username: postgres
5+
password: postgres
6+
liquibase:
7+
enabled: true

apps/provider/src/test/java/com/github/thorlauridsen/FlightControllerTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,35 @@
1111
import org.springframework.beans.factory.annotation.Autowired;
1212
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
1313
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
1415
import org.springframework.core.ParameterizedTypeReference;
1516
import org.springframework.http.MediaType;
17+
import org.springframework.test.context.ActiveProfiles;
1618
import org.springframework.test.web.servlet.client.RestTestClient;
19+
import org.testcontainers.containers.PostgreSQLContainer;
20+
import org.testcontainers.junit.jupiter.Container;
21+
import org.testcontainers.junit.jupiter.Testcontainers;
1722
import tools.jackson.databind.json.JsonMapper;
1823

1924
import static com.github.thorlauridsen.controller.BaseEndpoint.FLIGHT_BASE_ENDPOINT;
2025
import static org.junit.jupiter.api.Assertions.assertEquals;
2126
import static org.junit.jupiter.api.Assertions.assertNotNull;
2227

28+
/**
29+
* Test class for testing the FlightController.
30+
* A local Docker instance is required to run the tests as Testcontainers is used.
31+
*/
32+
@ActiveProfiles("postgres")
2333
@AutoConfigureRestTestClient
2434
@SpringBootTest
35+
@Testcontainers
2536
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
2637
class FlightControllerTest {
2738

39+
@Container
40+
@ServiceConnection
41+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:18");
42+
2843
@Autowired
2944
private RestTestClient restTestClient;
3045

apps/provider/src/test/java/com/github/thorlauridsen/HotelControllerTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,35 @@
1111
import org.springframework.beans.factory.annotation.Autowired;
1212
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
1313
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
1415
import org.springframework.core.ParameterizedTypeReference;
1516
import org.springframework.http.MediaType;
17+
import org.springframework.test.context.ActiveProfiles;
1618
import org.springframework.test.web.servlet.client.RestTestClient;
19+
import org.testcontainers.containers.PostgreSQLContainer;
20+
import org.testcontainers.junit.jupiter.Container;
21+
import org.testcontainers.junit.jupiter.Testcontainers;
1722
import tools.jackson.databind.json.JsonMapper;
1823

1924
import static com.github.thorlauridsen.controller.BaseEndpoint.HOTEL_BASE_ENDPOINT;
2025
import static org.junit.jupiter.api.Assertions.assertEquals;
2126
import static org.junit.jupiter.api.Assertions.assertNotNull;
2227

28+
/**
29+
* Test class for testing the HotelController.
30+
* A local Docker instance is required to run the tests as Testcontainers is used.
31+
*/
32+
@ActiveProfiles("postgres")
2333
@AutoConfigureRestTestClient
2434
@SpringBootTest
35+
@Testcontainers
2536
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
2637
class HotelControllerTest {
2738

39+
@Container
40+
@ServiceConnection
41+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:18");
42+
2843
@Autowired
2944
private RestTestClient restTestClient;
3045

apps/provider/src/test/java/com/github/thorlauridsen/RentalCarControllerTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,35 @@
1111
import org.springframework.beans.factory.annotation.Autowired;
1212
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
1313
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
1415
import org.springframework.core.ParameterizedTypeReference;
1516
import org.springframework.http.MediaType;
17+
import org.springframework.test.context.ActiveProfiles;
1618
import org.springframework.test.web.servlet.client.RestTestClient;
19+
import org.testcontainers.containers.PostgreSQLContainer;
20+
import org.testcontainers.junit.jupiter.Container;
21+
import org.testcontainers.junit.jupiter.Testcontainers;
1722
import tools.jackson.databind.json.JsonMapper;
1823

1924
import static com.github.thorlauridsen.controller.BaseEndpoint.RENTAL_CAR_BASE_ENDPOINT;
2025
import static org.junit.jupiter.api.Assertions.assertEquals;
2126
import static org.junit.jupiter.api.Assertions.assertNotNull;
2227

28+
/**
29+
* Test class for testing the RentalCarController.
30+
* A local Docker instance is required to run the tests as Testcontainers is used.
31+
*/
32+
@ActiveProfiles("postgres")
2333
@AutoConfigureRestTestClient
2434
@SpringBootTest
35+
@Testcontainers
2536
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
2637
class RentalCarControllerTest {
2738

39+
@Container
40+
@ServiceConnection
41+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:18");
42+
2843
@Autowired
2944
private RestTestClient restTestClient;
3045

0 commit comments

Comments
 (0)