メインコンテンツへ移動 / Skip to main content

Getting Started with Testcontainers for Production-like Testing

A practical guide to Testcontainers covering its background, workflow, strengths, and caveats for running production-like tests with real services.

Technology
Published on: September 20, 2025
Read time: 6 min
Author: Pochang Lab
Read time: 6 min

What Is Testcontainers? - A Practical Guide to "Real" Testing Environments

Today, we'll thoroughly explain Testcontainers, a tool that might feel a bit unfamiliar at first. I'll explain it in a lecture style, covering its history, background, specific examples, and pros and cons so that even beginners can get a clear picture.


1. Introduction: Testcontainers Is a Tool, Not a Concept

First, the most important thing to understand is that Testcontainers is not just a concept name, but a collection of OSS libraries. It's a Docker-based testing support tool created to solve the common problem: "I want to bring up real databases or message queues only during testing."

The Java implementation is particularly famous and works with JUnit using annotations like the following.

First, use the "@Testcontainers" annotation to declare that this test class manages containers. Then, use the "@Container" annotation to specify the container you want to start (e.g., PostgreSQL).

In other words, it operates as a JUnit extension library, not as an internal JUnit feature. This is clearly stated in the official documentation and explanations for each language version.

💡 Point: While Testcontainers' Java version is famous, official implementations also exist for Node.js, Python, and .NET. Choose the one that matches your language.

2. Historical Background: Why Testcontainers Was Born

2-1. Problems with Traditional Testing

Everyone, have you experienced any of these?

  • Mocks worked fine in tests but failed in production
  • Multiple people used a shared test database simultaneously, contaminating data
  • CI environment and developer local environment behaved differently

Traditional methods each have their advantages, but they had issues with "reproducibility" and "reliability".

2-2. Docker's Game-Changing Impact

Then Docker appeared. By spinning up lightweight, fast containers only during test execution and deleting them afterward, we could achieve:

  • "Same environment every time"
  • "Not affected by others' test results"
  • "Can use real dependency services"

Testcontainers is the concrete implementation of this idea.

🔄 Improved Reproducibility: By pinning Docker image tags, you can minimize situations like "it worked last week but not this week."

3. Basic Structure and Mechanism of Testcontainers

3-1. Library Characteristics

  • Docker Dependent: Internally operates Docker to start containers
  • Disposable (ephemeral): Starts at test beginning, deletes at test end
  • Multi-language Implementation: Available for Java, .NET, Node.js, Python, and more
  • Reuse Options: Basic is to rebuild for each test, but reuse settings are available for speed

3-2. JUnit Integration Example

java
@Testcontainers
class MyDatabaseTest {
    @Container
    static PostgreSQLContainer<?> postgres =
        new PostgreSQLContainer<>("postgres:16-alpine");

    @Test
    void testInsertAndQuery() {
        DataSource ds = getDataSource(postgres);
        runMigrations(ds);
        assertEquals(42, queryCount(ds));
    }
}
  • @Testcontainers declares "this class uses containers"
  • @Container specifies "start Postgres"
  • Automatically waits during tests and destroys after test completion

The important point here is that this functionality is not built into JUnit itself, but Testcontainers operates as an external library that extends JUnit.


4. Compatibility with Golden Master: Automating Before/After Comparisons

Here, let me introduce the concept of "Golden Master." This is a testing method that saves existing operation results as a "golden standard" and compares them with new version processing results.

For example, run batch on old infrastructure and save output (Before), process same input on new infrastructure and compare results (After). By automatically checking this difference, we can improve migration safety.

With Testcontainers, you can script:

  • Start old DB container for Before
  • Start new DB container for After
  • Process with same input data
  • Compare outputs or DB snapshots

This makes it very suitable for automating new/old comparison tests.

🧪 Golden Master Check Example
1. Start old version API with Testcontainers
2. Send same HTTP requests to new version
3. Save response body as JSON snapshot
4. Alert to Slack if there are differences

5. Organizing Pros and Cons

5-1. Advantages (Pros)

  1. Reproducibility: With fixed Docker images, anyone can get the same results anywhere
  2. Reliability: Can detect bugs that mocks can't catch, unique to real services
  3. Automation: Can complete startup to deletion in code, easy to integrate into CI/CD
  4. Independence: Isolated per test, so no data contamination occurs

5-2. Disadvantages (Cons)

  1. Startup Cost: Takes time to start containers
  2. Docker Dependency: Requires Docker in development environment and CI
  3. Version Management: Regular updates needed to avoid differences from production
  4. Network Restrictions: Requires ingenuity for introduction in closed corporate environments

6. Practical Usage Patterns and Best Practices

  1. 1 Test = 1 Container: High isolation but takes time. Limit to critical tests
  2. Shared per Test Class: Fast startup. Key is to define @Testcontainers as static and do proper initialization
  3. Docker Compose Integration: Start DB + MQ + cache together. Convenient when there are many peripheral services
  4. CI/CD Integration: Automate with GitHub Actions or GitLab CI. Design cache strategy combined with services
Operations Tip: In CI, reusing containers per Pull Request saves time. However, script reset procedures to prevent data contamination.

7. Common Pitfalls and How to Avoid Them

  • Tests occasionally fail → Insufficient startup waiting. Add health checks or SQL response confirmation
  • Slow → Lightweight images and introduce container reuse options
  • CI failures → Check permissions and network restrictions, get Docker socket sharing permission
  • Can't read differences → Normalize Golden Master outputs to comparable format before comparison

8. Fun Knowledge: Similarity to Frontend

The Golden Master concept is similar to "snapshot testing" in the frontend world. Capture UI states and save them, then detect differences in subsequent runs. Testcontainers can be said to extend this idea to the infrastructure level.

🎮 Similar Concept Example: Storybook's visual regression tests also compare differences with existing screenshots. Testcontainers is a toolkit that brings this concept to the backend.

9. Summary and Next Steps

  • Testcontainers is not a concept but an OSS library collection that uses Docker to start real services only during testing
  • Combined with Golden Master methods, it can automate new/old comparison verification
  • Advantages are reproducibility, reliability, and automation; disadvantages are startup cost and Docker dependency
  • Easy to introduce even in small projects, so start with database-dependent integration tests

Please try it once in a small test. By experiencing "tests that use the real thing", your testing design perspective should greatly expand.

Related Articles

September 6, 2026

GPT-6 Astra Arrives: What Changes When You Put It to Work in Codex?

Our first article produced with Astra examines GPT-6 in Codex, its differences from GPT-5.6, comparisons with Fable 5.1 and Opus 5, ARC-AGI-3 testing conditions, international reactions, and the AGI debate. Sources checked September 6, 2026.

TechnologyRead more
September 4, 2026

Building nagara: A Voice Player for AI Replies, Articles, and Novels

I wanted long Claude Code replies to be easier to listen to. This engineering story follows nagara, an open-source macOS player built with Swift and AivisSpeech, through quiet collection, sentence navigation, and pitch-preserving playback speed.

TechnologyRead more
September 2, 2026

You Don’t Have to Abandon Claude Desktop: The Practical Case for Claude Code CLI, Subagents, and Agent Teams

Subagents work in Claude Desktop's Code tab, so what still makes the CLI different? This practical guide explains CLI-only Agent Teams, Unix pipes, shell-environment continuity, which model and effort level each teammate and Subagent inherits, local-only configuration, Git exclusions, and copy-ready reviewer and log-watcher agents for ordinary Claude subscribers.

TechnologyRead more
September 2, 2026

Is Claude's Bypass Permissions Mode Actually Dangerous? Auto Mode, Enterprise Risk, and Safer Claude Code Operations

A source-based guide to Claude Code's Manual, Accept Edits, Plan, Auto, Don't Ask, and Bypass Permissions modes, including Desktop, CLI, Cowork, and an enterprise decision framework.

TechnologyRead more
August 31, 2026

Why AGENTS.md Won by Standardizing Almost Nothing — The 18-Month End of the AI Coding Rules War

Why did a landscape of tool-specific instruction files converge on AGENTS.md, a standard with no required fields? This evidence-based history follows its path from Amp's singular AGENT.md to Linux Foundation stewardship, rule-sync tools, invisible-Unicode attacks, and a practical 2026 setup.

TechnologyRead more