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

October 29, 2026

Fable 5.1 or Opus 5.5 in Claude Code? A Decision Matrix Built on Evidence, User Reports, and Effort

Compare Fable 5.1 and Opus 5.5 in Claude Code using official and independent evaluations, user reports, pricing, effort, and Ultracode. Includes a task matrix and a practical routing skill design.

TechnologyRead more
October 22, 2026

What Makes Gemini 4 Argon Different? — GPT-6, Claude Fable 5.1, and Opus 5.5 Compared

Compare Gemini 4 Argon with GPT-6.1 Sol, GPT-6 Astra, and Claude Fable 5.1, Opus/Sonnet 5.5: shared context, long output, video and audio input, introductory pricing, and practical choices for coding, analysis, and everyday work.

TechnologyRead more
October 22, 2026

PHP2Shell Response Guide — AWS, Legacy PHP, and Vulnerability Response in the AI Era

A primary-source guide to PHP2Shell disclosed on October 21, 2026, updated the night of October 22: exploitation attempts before disclosure, Japan’s government response and preventive outages worldwide, Amazon Linux fixes, AWS WAF limits, legacy backports, deployment verification, and AI-assisted discovery.

TechnologyRead more
October 21, 2026

Why Personal Data Breaches Keep Happening — Japan’s Incidents and What Businesses and Individuals Should Check

As of October 21, 2026: official disclosures from Times Car, Lawson, Furusato Choice and others, with practical guidance on AI-related threats, reporting, password hashes, MFA, AWS monitoring and personal responses.

TechnologyRead more
October 20, 2026

Ten AI Stories from the First Half of October 2026: Gemini 4 Argon, GPT-6.1 Sol, Claude Haiku 5.5 and Meta’s 816B Open Model

Ten AI stories from 1–19 October 2026 that matter to people who use, build or work alongside AI — checked against primary sources and reporting. New models and their prices, agents everywhere, a safety report, the EU AI Act timeline and new rules for voice actors’ voices.

TechnologyRead more

From the Pocho Lab

Try this next