メインコンテンツへ移動 / 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

August 10, 2026

Why the Benchmark King Breaks Code in the Field: The Real Reason Google Antigravity Isn't Catching On

Why does Google Antigravity cause regressions in the field? We explore the overwhelming cost performance of its $20 monthly plan and the mystery of why Google is lagging behind in AI coding agents, separating model intelligence from product quality.

TechnologyRead more
August 10, 2026

OpenAI Reaches Pentagon Agreement While Anthropic Faces Exclusion? Verification and Implications (As of March 4, 2026)

A source-first analysis of OpenAI's Pentagon agreements, evidence behind the Anthropic exclusion narrative, unresolved legal questions, and policy implications.

TechnologyRead more
August 10, 2026

What I Learned from Trading FX with LLMs

A detailed log of building an AI-powered automated FX trading system and running it live for a month, revealing what LLMs are bad at and where they actually shine.

TechnologyRead more
August 10, 2026

Why GPT-5.3-Codex-Spark Feels Fast: A Speed Architecture for Rewiring Developer Loops

This article maps the February 2026 Codex updates and explains what makes GPT-5.3-Codex-Spark feel fast, how to read benchmark claims, and how to combine Spark with GPT-5.3-Codex in real engineering workflows.

TechnologyRead more
August 10, 2026

Deconstructing Gemini Spark: 24/7 Always-On AI Agent Architecture

The paradigm shift of 'Autonomous Always-On AI' brought by Gemini Spark. We explore the Long-Horizon execution engine orchestrating Google Workspace and provide a direct comparison with Claude Cowork and Anti-Gravity.

TechnologyRead more