Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/andrecaiado/spring-boot-testcontainers
A Spring Boot project to demonstrate the use of testcontainers to implement integration tests with external systems
https://github.com/andrecaiado/spring-boot-testcontainers
integration-testing postgresql rabbitmq spring-boot testcontainers
Last synced: about 1 month ago
JSON representation
A Spring Boot project to demonstrate the use of testcontainers to implement integration tests with external systems
- Host: GitHub
- URL: https://github.com/andrecaiado/spring-boot-testcontainers
- Owner: andrecaiado
- Created: 2024-08-19T14:25:43.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-08-22T10:06:50.000Z (5 months ago)
- Last Synced: 2024-08-22T19:03:41.634Z (5 months ago)
- Topics: integration-testing, postgresql, rabbitmq, spring-boot, testcontainers
- Language: Java
- Homepage:
- Size: 195 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Spring Boot Testcontainers project
A Spring Boot project to demonstrate the use of testcontainers to implement integration tests with external systems
This README file will focus on the testcontainers features implementation. For more information about the other project features, please refer to the project template: [spring-boot-template](https://github.com/andrecaiado/spring-boot-template).
# Contents
- [Getting Started](#getting-started)
- [Main features](#main-features)
- [Dependencies and requirements](#dependencies-and-requirements)
- [Run the project](#run-the-project)
- [Run the tests](#run-the-tests)
- [System Under Test (SUT)](#system-under-test-sut)
- [External services configuration](#external-services-configuration)
- [RabbitMQ configuration](#rabbitmq-configuration)
- [Postgres configuration](#postgres-configuration)
- [Testcontainers configuration](#testcontainers-configuration)
- [Tests implementation](#tests-implementation)
- [RabbitMQ tests](#rabbitmq-tests)
- [Postgres tests](#postgres-tests)# Getting Started
This section provides an overview of the main features, necessary dependencies, and step-by-step instructions to help you get the application up and running quickly.
## Main features
The main features of this project are:
- Message consumer from a RabbitMQ queue
- Write the consumed messages to a Postgres database
- Integration tests with external services using Testcontainers
- Docker compose to launch external services (Postgres and RabbitMQ)## Dependencies and requirements
The following dependency are required to implement this project's main features:
```xml
org.springframework.boot
spring-boot-starter-amqporg.springframework.amqp
spring-rabbit-test
testorg.testcontainers
junit-jupiter
testorg.springframework.boot
spring-boot-testcontainers
testorg.testcontainers
rabbitmq
testorg.testcontainers
postgresql
test```
To launch and run the external services (Postgres, Prometheus and Grafana) in Docker containers, the following requirements are needed:
- [Docker](https://docs.docker.com/get-docker/)
- [Docker Compose](https://docs.docker.com/compose/install/)To run the project, the requirements are:
- [Java 17 (or higher)](https://www.oracle.com/java/technologies/javase-jdk17-downloads.html)
- [Maven](https://maven.apache.org/download.cgi)## Run the project
To run the project, execute the following command:
```shell
mvn spring-boot:run
```## Run the integration tests
To run the tests, execute the following command:
```shell
mvn failsafe:integration-test
```The application will be available at [http://localhost:8080](http://localhost:8080).
The external services (Postgres and RabbitMQ) configured in the [docker-compose.yaml](docker-compose.yaml) file will automatically be launched due to the `spring-boot-docker-compose` dependency.
In any case, the external services can also be launched manually by running on of the following command:
```shell
# Start all the external services
docker compose up -d
``````shell
# Start a specific external service
docker compose up -d
# Replace with the service you want to start (postgres or rabbitmq)
```# System Under Test (SUT)
The System Under Test (SUT) is a simple Spring Boot application with the following use cases:
- Consume messages from a RabbitMQ queue and write them to a Postgres database.
- Exposes endpoints to execute CRUD operations on the database.![sut.png](src%2Fmain%2Fresources%2Fsut.png)
The integration tests to be implemented will use Testcontainers to launch the external services (Postgres and RabbitMQ) and test the application's interaction with these services.
The tests will cover the following scenarios:
- The application's ability to consume messages from a RabbitMQ queue and write them to a Postgres database.
- The application's ability to execute CRUD operations on the database.
# External services configuration
This section provides an overview of the configuration of the external services (Postgres and RabbitMQ).
Because we are using `spring-boot-docker-compose` dependency, Spring Boot will take care of the following:
- When the application is started, the services defined in the [docker-compose.yaml](docker-compose.yaml) file will be automatically started.
- The connection details for the services will be created and made available to the application, that's why we don't need to specify any connection details in the application configuration files.
**Note:** This also applies to the integration tests. The Testcontainers will be launched before the tests are executed, and the connection details will be made available to the tests.
For more details on the `spring-boot-docker-compose` dependency, please refer to the [Docker Compose Support documentation](https://spring.io/blog/2023/06/21/docker-compose-support-in-spring-boot-3-1).
## RabbitMQ configuration
The RabbitMQ service was added and configured in the [docker-compose.yaml](docker-compose.yaml).
On startup, 2 configuration files are mounted to the container:
- [rabbitmq.config](docker/rabbitmq/rabbitmq.config)
- [definitions.json](docker/rabbitmq/definitions.json)The `rabbitmq.config` file is used to specify the location of the `definitions.json` file.
The `definitions.json` file contains the RabbitMQ configuration settings, such as:
- Users and permissions
- Virtual hosts
- Exchanges
- Queues
- BindingsThe RabbitMQ management console is available at [http://localhost:15672](http://localhost:15672) with the default credentials:
- Username: guest
- Password: guestThe application connection to the RabbitMQ service and the RabbitMQ queues, exchanges, and bindings are configured in:
- The [application.yml](src/main/resources/application.yml) file for the main application.
- The [application-integration-test.yml](src/test/resources/application-integration-test.yml) file for the integration tests.
## Postgres configuration
The Postgres service was added and configured in the [docker-compose.yaml](docker-compose.yaml).
# Testcontainers configuration
The Testcontainers were configured at the tests level.
The following annotations were used to configure the Testcontainers:
- The `@Testcontainers` annotation is used to enable the Testcontainers support in the test class.
- The `@ExtendWith(OutputCaptureExtension.class)` annotation is used to capture the output of the application's logs.
- The `@Container` annotation is used to define the Testcontainers that will be launched before the tests are executed.
- The `@ServiceConnection` discovers the type of container that is annotated and creates a ConnectionDetails bean that can be used to connect to the service. The details of the connection are, once again, made available by the `spring-boot-docker-compose` dependency.
Below is an example of the configuration of the RabbitMQ and Postgres containers that can be found in the [EmployeeRabbitMQIT.java](src%2Fintegration-test%2Fjava%2Fcom.example.springboottemplate%2FEmployeeRabbitMQIT.java) file:
```java
@ActiveProfiles("integration-test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@ExtendWith(OutputCaptureExtension.class)
public class EmployeeRabbitMQIT {
...@Container
@ServiceConnection
static PostgreSQLContainer> postgres = new PostgreSQLContainer<>(
"postgres:16.3-alpine"
);@Container
@ServiceConnection
static RabbitMQContainer rabbitMQContainer = new RabbitMQContainer(
"rabbitmq:3.13.6-management-alpine"
).withCopyFileToContainer(
MountableFile.forClasspathResource("rabbitmq/rabbitmq.conf"),
"/etc/rabbitmq/rabbitmq.conf"
).withCopyFileToContainer(
MountableFile.forClasspathResource("rabbitmq/definitions.json"),
"/etc/rabbitmq/definitions.json"
);
...
}
```# Tests implementation
This section provides an overview of the tests implemented to validate the application's interaction with the external services (RabbitMQ and Postgres).
## RabbitMQ tests
To test the application's ability to consume messages from a RabbitMQ queue, the implemented test has the following steps:
1. A message is sent to the RabbitMQ queue.
2. The test waits for the message to be consumed by the application and verifies if specific log messages are printed to the console.
Below is an example of the test implementation that can be found in the [EmployeeRabbitMQIT.java](src/test/java/com/acaiado/employeerabbitmq/EmployeeRabbitMQIT.java) file:
```java
@Test
void testCreateEmployee(CapturedOutput output) {
CreateUpdateEmployeeDto createUpdateEmployeeDto = getCreateUpdateEmployeeDto();producer.sendMessageCreateEmployee(createUpdateEmployeeDto);
Pattern pattern = Pattern.compile("\\w*Received message with payload: CreateUpdateEmployeeDto\\(firstName=John, lastName=Doe, age=30, designation=Software Engineer, phoneNumber=1234567890, joinedOn=2021-01-01, address=123, Baker Street, London, dateOfBirth=1979-01-01\\) on \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\w*");
await().atMost(10, TimeUnit.SECONDS)
.until(findPatternInOutput(output, pattern), is(true));Pattern pattern2 = Pattern.compile("\\w*Employee with id: \\d+ saved successfully\\w*");
await().atMost(10, TimeUnit.SECONDS)
.until(findPatternInOutput(output, pattern2), is(true));
}private Callable findPatternInOutput(CapturedOutput output, Pattern pattern) {
return () -> pattern.matcher(output.getOut()).find();
}
```## Postgres tests
To test the application's ability to execute CRUD operations on the database, the implemented test has the following steps:
1. An employee is created in the database.
2. The test verifies the body of the response returned by the application when the employee is created.The test implementation that can be found in the [EmployeePostgresIT.java](src/test/java/com/acaiado/employeerabbitmq/EmployeePostgresIT.java) file.