Ya hace 3 años, sobre Agosto de 2020 vi un post sobre cómo realizar pruebas unitarias con contenedores. Y aunque tuve la intención de hacer un post, nunca llegue a hacerlo. Pero ahora tras ver cómo funcionan las pruebas con Quarkus, del cual intentaré hablar más adelante, me he interesado en sacar este post.
En múltiples de los posts que he realizado, he utilizado siempre contenedores para poder realizar las pruebas, y poder comprobar el ejemplo práctico. Normalmente dejando un docker-compose.yml que permitiese levantar y configurar los sistemas externos con los cuales iba a trabajar la aplicación.
Ahora vamos a hacer algo parecido Y para llevarlo a cabo utilizaremos Testcontainers. Es una librería Java que nos permite crear instancias de Docker y manejarlas en base a nuestro interés. En el ejemplo utilizaremos las siguientes librerías:
- org.testcontainers:testcontainers:1.16.0
- org.testcontainers:junit-jupiter:1.16.0
- org.testcontainers:mysql:1.16.0
- org.apache.camel:camel-test-spring-junit5:3.16.0
- org.springframework.boot:spring-boot-starter-test:2.5.1
Para empezarla a utilizar, usaremos principalmente dos anotaciones:
- @Testcontainers: que nos permite utilizar Testcontainers con JUnit 5.
- @Containers: Nos permite indicar a las instancias de contenedores que queremos que sean gestionadas por Testcontainers. Aunque como veremos más adelante podemos utilizar Testcontainers sin ella.
- La instancia de GenericContainer nos permitirá indicar la imagen de ActiveMQ a crear y los puertos a exponer.
- Crear un método BeforeAll que permita arrancar el contenedor y el puerto vinculado externo.
- Modificar la configuración de los componentes que realizan la comunicación con el sistema externo. En Spring Boot lo podemos hacer fácilmente con un método anotado con @DynamicPropertySource.
@Testcontainers @CamelSpringBootTest @SpringBootTest(classes = ApacheCamelTestApplication.class) @Log4j2 public class ApacheActiveMqRouterTest { @Autowired ProducerTemplate producer; @Container private static GenericContainer container = new GenericContainer("rmohr/activemq").withExposedPorts(61616, 8161); private static Integer tcpPort; @BeforeAll public static void beforeAll() { container.start(); tcpPort = container.getMappedPort(61616); } @DynamicPropertySource static void replaceProperties(DynamicPropertyRegistry registry) { registry.add("activemq.broker-url", () -> "tcp://localhost:" + tcpPort); } @Test public void amqTo01() throws InterruptedException { producer.sendBody("direct:SendToPublic", "mensaje "); } }
@Testcontainers @CamelSpringBootTest @SpringBootTest(classes = {ApacheCamelTestApplication.class}) @Slf4j public class ApacheMySQLRouterTest{ static final DockerImageName MYSQL_57_IMAGE = DockerImageName.parse("mysql:5.7.34"); static MySQLContainer<?> database = new MySQLContainer<>(MYSQL_57_IMAGE) .withInitScript("scripts/init_mysql.sql") .withDatabaseName("library").withLogConsumer(new Slf4jLogConsumer(log));
@Autowired ProducerTemplate producer;@BeforeAll public static void beforeAll() throws IOException { database.start(); } @DynamicPropertySource static void databaseProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", database::getJdbcUrl); registry.add("spring.datasource.username", database::getUsername); registry.add("spring.datasource.password", database::getPassword); } @Test public void getBookById() throws InterruptedException { producer.sendBodyAndHeader("direct:getBookById", null, "id", 1); } }
- 1.18: Genero la excepción NoSuchMethodError asociada al método optionallyMapResourceParameterAsVolume.
- 1.17: Genero ClassNotFoundException: asociado a la clase org.testcontainers.shaded.org.apache.commons.lang.StringUtils
@SpringBootTest @Testcontainers @CamelSpringBootTest @Slf4j public class TestcontainersConf { public static final DockerImageName MYSQL_57_IMAGE = DockerImageName.parse("mysql:5.7.34"); static GenericContainer<?> container = new GenericContainer<>("rmohr/activemq").withExposedPorts(61616, 8161); static MySQLContainer<?> database = new MySQLContainer<>(MYSQL_57_IMAGE) .withInitScript("scripts/init_mysql.sql") .withDatabaseName("library").withLogConsumer(new Slf4jLogConsumer(log)); @BeforeAll public static void beforeAll() { container.start(); database.start(); } @DynamicPropertySource static void replaceProperties(DynamicPropertyRegistry registry) { registry.add("activemq.broker-url", () -> "tcp://localhost:" + container.getMappedPort(61616)); registry.add("spring.datasource.url", database::getJdbcUrl); registry.add("spring.datasource.username", database::getUsername); registry.add("spring.datasource.password", database::getPassword); } } // ............................ public class ApacheMySQLRouterTest extends TestcontainersConf{ @Autowired ProducerTemplate producer; @Test public void getBookById() throws InterruptedException { producer.sendBodyAndHeader("direct:getBookById", null, "id", 1); } }
No hay comentarios:
Publicar un comentario