Skip to content

testcontainers integrados con Spring #1

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# TestContainers en el contexto de SpringBootTest

> Link al post:
Este proyecto es la base del post [Integrando TestContainers en el contexto de Spring en nuestros tests](https://dev.to/adevintaspain/integrando-testcontainers-en-el-contexto-de-spring-en-nuestros-tests-5b7d) para jugar con distintas formas de integrar TestContainers en el flujo de ejecución de tests con [Junit5](https://junit.org/junit5/docs/current/user-guide/) para un servicio desarrollado con [Spring Boot](https://spring.io/projects/spring-boot), dejando al final que sea Spring quien haga el trabajo por nosotros, aprovechándonos de las características del ciclo de vida del ApplicationContext durante la ejecución de los tests, focalizado en la asignación de puertos dinámicos para las infraestructuras externas levantadas localmente para los tests.

Como referencia a las pruebas comentadas en el post, se puede consultar los cambios que aplicarían en cada caso en estas PR:

1. Antes de integrar test containers, ya se puede probar el proyecto usando docker-compose
> - :confused: _[TestContainers integrados con JUnit](https://github.com/alextremp/testcontainers-springboot-demo/pull/3/files)_
> - :rocket: _[TestContainers singleton gestionados manualmente](https://github.com/alextremp/testcontainers-springboot-demo/pull/2/files)_
> - :heart_eyes: _[TestContainers gestionados por Spring](https://github.com/alextremp/testcontainers-springboot-demo/pull/1/files)_


La rama master es operativa pero sin TestContainers, por lo que para poder ejecutar los tests debe levantarse las infraestructuras externas con docker compose:

```
docker-compose up -d
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.github.alextremp.testcontainersdemo.infrastructure;

import com.github.alextremp.testcontainersdemo.infrastructure.testcontainers.DockerizedInfrastructure;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = {DockerizedInfrastructure.class, Application.class})
abstract class AbstractIntegrationTest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;

import static java.lang.String.format;
import static org.awaitility.Awaitility.await;

@SpringBootTest
@Sql("/fixtures/message-store-db/clean.sql")
class ApplicationTest {
class ApplicationTest extends AbstractIntegrationTest {

@Autowired
private RabbitTemplate rabbitTemplate;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.github.alextremp.testcontainersdemo.infrastructure.testcontainers;

import java.io.File;
import javax.annotation.PreDestroy;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.testcontainers.containers.DockerComposeContainer;

import static java.lang.String.format;

@Component
public class DockerizedInfrastructure {

private static final String MESSAGE_STORE_DB_SERVICE = "message-store-db";
private static final Integer MESSAGE_STORE_DB_PORT = 5432;
private static final String SPRING_MESSAGE_STORE_DB_PORT = "message-store-db.port";

private static final String MQ_SERVER_SERVICE = "mq-server";
private static final Integer MQ_SERVER_PORT = 5672;
private static final String SPRING_MQ_SERVER_PORT = "mq-server.port";

private final DockerComposeContainer dockerServices;

public DockerizedInfrastructure(ConfigurableApplicationContext configurableApplicationContext) {
// Inicializamos los servicios de docker-compose
dockerServices = new DockerComposeContainer<>(new File("docker-compose.yml"))
.withLocalCompose(true)
.withExposedService(MESSAGE_STORE_DB_SERVICE, MESSAGE_STORE_DB_PORT)
.withExposedService(MQ_SERVER_SERVICE, MQ_SERVER_PORT);

// Arrancamos los servicios dockerizados
dockerServices.start();

// Refrescamos el contexto de Spring con los puertos designados
TestPropertyValues.of(
format("%s=%s",
SPRING_MESSAGE_STORE_DB_PORT,
dockerServices.getServicePort(MESSAGE_STORE_DB_SERVICE, MESSAGE_STORE_DB_PORT)),
format("%s=%s",
SPRING_MQ_SERVER_PORT,
dockerServices.getServicePort(MQ_SERVER_SERVICE, MQ_SERVER_PORT))
).applyTo(configurableApplicationContext.getEnvironment());
}

@PreDestroy
void preDestroy() {
// Apagamos los servicios dockerizados
dockerServices.stop();
}
}