mirror of
https://github.com/docker/docs.git
synced 2026-03-29 15:28:51 +07:00
## Description Migrate 17 Testcontainers guides from testcontainers.com into the Docker docs site, covering Java (14 guides), .NET (2 guides), and Node.js (1 guide). This follows up on PR #24450 which added the initial Go and Python guides. Each guide is converted from AsciiDoc to Hugo Markdown, split into multi-chapter stepper navigation, updated to the latest Testcontainers API, and verified with passing tests running in containers. Java guides use testcontainers-java 2.0.4 with the new 2.x Maven coordinates and package names (e.g., `testcontainers-postgresql`, `org.testcontainers.postgresql.PostgreSQLContainer`). The Quarkus guide uses Quarkus 3.22.3 with TC 1.x managed by the Quarkus BOM, since no released Quarkus version ships TC 2.x yet. ## How to test All code snippets have been verified by running each guide's source repository tests inside Docker containers with the Docker socket mounted. To re-run the verification, use the `/testcontainers-guides-migrator` skill included in this PR (`.claude/skills/testcontainers-guides-migrator/SKILL.md`). The skill's Step 6 documents the exact container commands and macOS Docker Desktop workarounds (host override, docker-java API version, etc.) needed to run each language's tests: ``` /testcontainers-guides-migrator I want you to verify all the guides in this branch. Do a full review, verifying that all code snippets compile, the code is executable, and ALL the tests pass. Run them as docker containers, never locally. ``` ## Related issues or tickets Supersedes #24450 (expanded from 2 guides to all 19) ## Reviews - [ ] Technical review - [ ] Editorial review - [ ] Product review --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
4.0 KiB
Markdown
114 lines
4.0 KiB
Markdown
---
|
|
title: Write tests with Testcontainers
|
|
linkTitle: Write tests
|
|
description: Test the Spring Boot Kafka listener using Testcontainers Kafka and MySQL modules with Awaitility.
|
|
weight: 20
|
|
---
|
|
|
|
To test the Kafka listener, you need a running Kafka broker and a MySQL
|
|
database, plus a started Spring context. Testcontainers spins up both services
|
|
in Docker containers and `@DynamicPropertySource` connects them to Spring.
|
|
|
|
## Write the test
|
|
|
|
Create `ProductPriceChangedEventHandlerTest.java`:
|
|
|
|
```java
|
|
package com.testcontainers.demo;
|
|
|
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.awaitility.Awaitility.await;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.time.Duration;
|
|
import java.util.Optional;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.kafka.core.KafkaTemplate;
|
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
import org.springframework.test.context.DynamicPropertySource;
|
|
import org.springframework.test.context.TestPropertySource;
|
|
import org.testcontainers.kafka.ConfluentKafkaContainer;
|
|
import org.testcontainers.junit.jupiter.Container;
|
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
|
|
@SpringBootTest
|
|
@TestPropertySource(
|
|
properties = {
|
|
"spring.kafka.consumer.auto-offset-reset=earliest",
|
|
"spring.datasource.url=jdbc:tc:mysql:8.0.32:///db",
|
|
}
|
|
)
|
|
@Testcontainers
|
|
class ProductPriceChangedEventHandlerTest {
|
|
|
|
@Container
|
|
static final ConfluentKafkaContainer kafka =
|
|
new ConfluentKafkaContainer("confluentinc/cp-kafka:7.8.0");
|
|
|
|
@DynamicPropertySource
|
|
static void overrideProperties(DynamicPropertyRegistry registry) {
|
|
registry.add("spring.kafka.bootstrap-servers", kafka::getBootstrapServers);
|
|
}
|
|
|
|
@Autowired
|
|
private KafkaTemplate<String, Object> kafkaTemplate;
|
|
|
|
@Autowired
|
|
private ProductRepository productRepository;
|
|
|
|
@BeforeEach
|
|
void setUp() {
|
|
Product product = new Product(null, "P100", "Product One", BigDecimal.TEN);
|
|
productRepository.save(product);
|
|
}
|
|
|
|
@Test
|
|
void shouldHandleProductPriceChangedEvent() {
|
|
ProductPriceChangedEvent event = new ProductPriceChangedEvent(
|
|
"P100",
|
|
new BigDecimal("14.50")
|
|
);
|
|
|
|
kafkaTemplate.send("product-price-changes", event.productCode(), event);
|
|
|
|
await()
|
|
.pollInterval(Duration.ofSeconds(3))
|
|
.atMost(10, SECONDS)
|
|
.untilAsserted(() -> {
|
|
Optional<Product> optionalProduct = productRepository.findByCode(
|
|
"P100"
|
|
);
|
|
assertThat(optionalProduct).isPresent();
|
|
assertThat(optionalProduct.get().getCode()).isEqualTo("P100");
|
|
assertThat(optionalProduct.get().getPrice())
|
|
.isEqualTo(new BigDecimal("14.50"));
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
Here's what the test does:
|
|
|
|
- `@SpringBootTest` starts the full Spring application context.
|
|
- The Testcontainers special JDBC URL (`jdbc:tc:mysql:8.0.32:///db`) in
|
|
`@TestPropertySource` spins up a MySQL container and configures it as the
|
|
datasource automatically.
|
|
- `@Testcontainers` and `@Container` manage the lifecycle of the Kafka
|
|
container. `@DynamicPropertySource` registers the Kafka bootstrap servers
|
|
with Spring so that the producer and consumer connect to the test container.
|
|
- `@BeforeEach` creates a `Product` record in the database before each test.
|
|
- The test sends a `ProductPriceChangedEvent` to the `product-price-changes`
|
|
topic using `KafkaTemplate`. Spring Boot converts the object to JSON using
|
|
`JsonSerializer`.
|
|
- Because Kafka message processing is asynchronous, the test uses
|
|
[Awaitility](http://www.awaitility.org/) to poll every 3 seconds (up to a
|
|
maximum of 10 seconds) until the product price in the database matches the
|
|
expected value.
|
|
- The property `spring.kafka.consumer.auto-offset-reset` is set to `earliest`
|
|
so that the listener consumes messages even if they're sent to the topic
|
|
before the listener is ready. This setting is helpful when running tests.
|