## 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>
6.2 KiB
title, linkTitle, description, weight
| title | linkTitle | description | weight |
|---|---|---|---|
| Create the Micronaut project | Create the project | Set up a Micronaut project with an external REST API integration using declarative HTTP clients. | 10 |
Set up the project
Create a Micronaut project from Micronaut Launch by selecting the http-client, micronaut-test-rest-assured, and testcontainers features.
Alternatively, clone the guide repository.
After generating the project, add the WireMock and Testcontainers
WireMock libraries as test dependencies. The key dependencies in pom.xml
are:
<parent>
<groupId>io.micronaut.platform</groupId>
<artifactId>micronaut-parent</artifactId>
<version>4.1.2</version>
</parent>
<properties>
<jdk.version>17</jdk.version>
<micronaut.version>4.1.2</micronaut.version>
<micronaut.runtime>netty</micronaut.runtime>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-client</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-server-netty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.serde</groupId>
<artifactId>micronaut-serde-jackson</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>3.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock.integrations.testcontainers</groupId>
<artifactId>wiremock-testcontainers-module</artifactId>
<version>1.0-alpha-13</version>
<scope>test</scope>
</dependency>
</dependencies>
This guide builds an application that manages video albums. A third-party REST API handles photo assets. For demonstration purposes, the application uses the publicly available JSONPlaceholder API as a photo service.
The application exposes a GET /api/albums/{albumId} endpoint that calls the
photo service to fetch photos for a given album.
WireMock is a tool for building mock APIs.
Testcontainers provides a
WireMock module that runs
WireMock as a Docker container.
Create the Album and Photo models
Create Album.java using Java records. Annotate both records with @Serdeable
to allow serialization and deserialization:
package com.testcontainers.demo;
import io.micronaut.serde.annotation.Serdeable;
import java.util.List;
@Serdeable
public record Album(Long albumId, List<Photo> photos) {}
@Serdeable
record Photo(Long id, String title, String url, String thumbnailUrl) {}
Create the PhotoServiceClient
Micronaut provides declarative HTTP client support. Create an interface with a method that fetches photos for a given album ID:
package com.testcontainers.demo;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.client.annotation.Client;
import java.util.List;
@Client(id = "photosapi")
interface PhotoServiceClient {
@Get("/albums/{albumId}/photos")
List<Photo> getPhotos(@PathVariable Long albumId);
}
The @Client(id = "photosapi") annotation ties this client to a named
configuration. Add the following property to
src/main/resources/application.properties to set the base URL:
micronaut.http.services.photosapi.url=https://jsonplaceholder.typicode.com
Create the REST API endpoint
Create AlbumController.java:
package com.testcontainers.demo;
import static io.micronaut.scheduling.TaskExecutors.BLOCKING;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.scheduling.annotation.ExecuteOn;
@Controller("/api")
class AlbumController {
private final PhotoServiceClient photoServiceClient;
AlbumController(PhotoServiceClient photoServiceClient) {
this.photoServiceClient = photoServiceClient;
}
@ExecuteOn(BLOCKING)
@Get("/albums/{albumId}")
public Album getAlbumById(@PathVariable Long albumId) {
return new Album(albumId, photoServiceClient.getPhotos(albumId));
}
}
Here's what this controller does:
@Controller("/api")maps the controller to the/apipath.- Constructor injection provides a
PhotoServiceClientbean. @ExecuteOn(BLOCKING)offloads blocking I/O to a separate thread pool so it doesn't block the event loop.@Get("/albums/{albumId}")maps thegetAlbumById()method to an HTTP GET request.
This endpoint calls the photo service for a given album ID and returns a response like:
{
"albumId": 1,
"photos": [
{
"id": 51,
"title": "non sunt voluptatem placeat consequuntur rem incidunt",
"url": "https://via.placeholder.com/600/8e973b",
"thumbnailUrl": "https://via.placeholder.com/150/8e973b"
},
{
"id": 52,
"title": "eveniet pariatur quia nobis reiciendis laboriosam ea",
"url": "https://via.placeholder.com/600/121fa4",
"thumbnailUrl": "https://via.placeholder.com/150/121fa4"
}
]
}