## 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 |
|---|---|---|---|
| Write tests with Testcontainers | Write tests | Test jOOQ repositories using Testcontainers with the @JooqTest slice and @SpringBootTest. | 20 |
Before writing the tests, create an SQL script to seed test data at
src/test/resources/test-data.sql:
DELETE FROM comments;
DELETE FROM posts;
DELETE FROM users;
INSERT INTO users(id, name, email) VALUES
(1, 'Siva', 'siva@gmail.com'),
(2, 'Oleg', 'oleg@gmail.com');
INSERT INTO posts(id, title, content, created_by, created_at) VALUES
(1, 'Post 1 Title', 'Post 1 content', 1, CURRENT_TIMESTAMP),
(2, 'Post 2 Title', 'Post 2 content', 2, CURRENT_TIMESTAMP);
INSERT INTO comments(id, name, content, post_id, created_at) VALUES
(1, 'Ron', 'Comment 1', 1, CURRENT_TIMESTAMP),
(2, 'James', 'Comment 2', 1, CURRENT_TIMESTAMP),
(3, 'Robert', 'Comment 3', 2, CURRENT_TIMESTAMP);
Test with the @JooqTest slice
The @JooqTest annotation loads only the persistence layer components and
auto-configures jOOQ's DSLContext. Use the Testcontainers special JDBC URL
to start a Postgres container.
Create UserRepositoryJooqTest.java:
package com.testcontainers.demo.domain;
import static org.assertj.core.api.Assertions.assertThat;
import org.jooq.DSLContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
import org.springframework.test.context.jdbc.Sql;
@JooqTest(
properties = {
"spring.test.database.replace=none",
"spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db",
}
)
@Sql("/test-data.sql")
class UserRepositoryJooqTest {
@Autowired
DSLContext dsl;
UserRepository repository;
@BeforeEach
void setUp() {
this.repository = new UserRepository(dsl);
}
@Test
void shouldCreateUserSuccessfully() {
User user = new User(null, "John", "john@gmail.com");
User savedUser = repository.createUser(user);
assertThat(savedUser.id()).isNotNull();
assertThat(savedUser.name()).isEqualTo("John");
assertThat(savedUser.email()).isEqualTo("john@gmail.com");
}
@Test
void shouldGetUserByEmail() {
User user = repository.getUserByEmail("siva@gmail.com").orElseThrow();
assertThat(user.id()).isEqualTo(1L);
assertThat(user.name()).isEqualTo("Siva");
assertThat(user.email()).isEqualTo("siva@gmail.com");
}
}
Here's what the test does:
@JooqTestloads only the persistence layer and auto-configuresDSLContext.- The Testcontainers special JDBC URL
(
jdbc:tc:postgresql:16-alpine:///db) starts a PostgreSQL container automatically. - Because
flyway-coreis on the classpath, Spring Boot runs the Flyway migrations fromsrc/main/resources/db/migrationon startup. @Sql("/test-data.sql")loads the test data before each test.- The
UserRepositoryis instantiated manually with the injectedDSLContext.
Integration test with @SpringBootTest
For a full integration test, use @SpringBootTest with the Testcontainers
@ServiceConnection support introduced in Spring Boot 3.1.
Create UserRepositoryTest.java:
package com.testcontainers.demo.domain;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.test.context.jdbc.Sql;
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@SpringBootTest
@Sql("/test-data.sql")
@Testcontainers
class UserRepositoryTest {
@Container
@ServiceConnection
static PostgreSQLContainer postgres = new PostgreSQLContainer(
"postgres:16-alpine"
);
@Autowired
UserRepository repository;
@Test
void shouldCreateUserSuccessfully() {
User user = new User(null, "John", "john@gmail.com");
User savedUser = repository.createUser(user);
assertThat(savedUser.id()).isNotNull();
assertThat(savedUser.name()).isEqualTo("John");
assertThat(savedUser.email()).isEqualTo("john@gmail.com");
}
@Test
void shouldGetUserByEmail() {
User user = repository.getUserByEmail("siva@gmail.com").orElseThrow();
assertThat(user.id()).isEqualTo(1L);
assertThat(user.name()).isEqualTo("Siva");
assertThat(user.email()).isEqualTo("siva@gmail.com");
}
}
Here's what the test does:
@SpringBootTestloads the entire application context, soUserRepositoryis injected directly.@Testcontainersand@Containermanage the PostgreSQL container lifecycle.@ServiceConnectionauto-configures the datasource properties from the running container, replacing the need for@DynamicPropertySource.@Sql("/test-data.sql")initializes the test data.
Test PostRepository
Test the PostRepository that fetches complex object graphs using the
Testcontainers special JDBC URL.
Create PostRepositoryTest.java:
package com.testcontainers.demo.domain;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
@SpringBootTest(
properties = {
"spring.test.database.replace=none",
"spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db",
}
)
@Sql("/test-data.sql")
class PostRepositoryTest {
@Autowired
PostRepository repository;
@Test
void shouldGetPostById() {
Post post = repository.getPostById(1L).orElseThrow();
assertThat(post.id()).isEqualTo(1L);
assertThat(post.title()).isEqualTo("Post 1 Title");
assertThat(post.content()).isEqualTo("Post 1 content");
assertThat(post.createdBy().id()).isEqualTo(1L);
assertThat(post.createdBy().name()).isEqualTo("Siva");
assertThat(post.createdBy().email()).isEqualTo("siva@gmail.com");
assertThat(post.comments()).hasSize(2);
}
}
This test verifies that getPostById loads the post along with its creator
and comments in a single query using jOOQ's MULTISET feature.