Testing Docker Containers — Integration & End-to-End Testing Guide
Testing Docker containers ensures that your containerized application runs correctly in the target environment — with the right file system, environment variables, exposed ports, and service dependencies. In this guide, you will learn how to validate container images with structure tests, run integration tests against multi-service Docker Compose stacks, and automate end-to-end tests in CI/CD pipelines. The DodaZIP backend runs a full container test suite before every deployment, catching missing dependencies and misconfigured environments early.
Learning Path
flowchart LR A[Docker Basics] --> B[Docker Compose] B --> C[Testing Containers
You are here] C --> D[Testing Kubernetes] D --> E[CI/CD Pipelines] style C fill:#f90,color:#fff
Container Structure Tests
Validate the image content and configuration before running it:
# container-structure-test.yaml
schemaVersion: "2.0.0"
fileExistenceTests:
- name: "nginx binary"
path: "/usr/sbin/nginx"
shouldExist: true
isExecutable: true
commandTests:
- name: "nginx version"
command: "nginx"
args: ["-v"]
expectedError: ["nginx version: nginx/1.25.*"]
metadataTest:
env:
- key: "NGINX_PORT"
value: "80"
exposedPorts: ["80"]
entrypoint: ["/docker-entrypoint.sh"]
Run the test:
container-structure-test test \
--image nginx:1.25 \
--config container-structure-test.yaml
Expected output:
===================================
======= TEST RESULTS ==============
===================================
[PASS] nginx binary exists and is executable
[PASS] nginx version matches expected pattern
[PASS] environment variable NGINX_PORT=80
[PASS] exposed ports include 80
Integration Tests with Docker Compose
Test your service against its real dependencies:
# docker-compose.test.yml
services:
app:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/testdb
- REDIS_URL=redis://redis:6379
db:
image: postgres:16
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=testdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d testdb"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
test:
build:
context: .
dockerfile: Dockerfile.test
depends_on:
app:
condition: service_started
environment:
- API_URL=http://app:8080
Run with:
docker compose -f docker-compose.test.yml up --build --abort-on-container-exit
Writing Integration Tests
Test the running container via its exposed API:
import requests
import time
import os
BASE_URL = os.getenv("API_URL", "http://localhost:8080")
def wait_for_service(url, timeout=30):
start = time.time()
while time.time() - start < timeout:
try:
r = requests.get(f"{url}/health", timeout=2)
if r.status_code == 200:
return True
except requests.ConnectionError:
pass
time.sleep(1)
return False
def test_health_endpoint():
assert wait_for_service(BASE_URL), "Service did not start in time"
r = requests.get(f"{BASE_URL}/health")
assert r.status_code == 200
data = r.json()
assert data["status"] == "ok"
assert "db" in data and data["db"] == "connected"
assert "redis" in data and data["redis"] == "connected"
print("Health check passed")
def test_create_resource():
r = requests.post(f"{BASE_URL}/users", json={"name": "Alice", "email": "alice@test.com"})
assert r.status_code == 201
data = r.json()
assert "id" in data
print(f"Created user with ID: {data['id']}")
def test_get_resource():
r = requests.get(f"{BASE_URL}/users/1")
assert r.status_code == 200
data = r.json()
assert data["name"] == "Alice"
print("Get user passed")
if __name__ == "__main__":
test_health_endpoint()
test_create_resource()
test_get_resource()
print("All container integration tests passed")
Expected output:
Health check passed
Created user with ID: 1
Get user passed
All container integration tests passed
Testing Container Logs and Errors
Verify that the container logs errors correctly:
import subprocess
def test_container_logs():
result = subprocess.run(
["docker", "logs", "test_app_1"],
capture_output=True, text=True
)
assert "ERROR" not in result.stdout
assert "failed" not in result.stdout.lower()
assert "Server started" in result.stdout
print("Container log check passed")
test_container_logs()
Testing Image Size and Layers
import subprocess, json
def test_image_size():
result = subprocess.run(
["docker", "inspect", "myapp:latest", "--format", "{{json .Size}}"],
capture_output=True, text=True
)
size_bytes = int(result.stdout.strip())
size_mb = size_bytes / (1024 * 1024)
assert size_mb < 500, f"Image too large: {size_mb:.0f}MB"
print(f"Image size: {size_mb:.0f}MB (limit: 500MB)")
def test_layer_count():
result = subprocess.run(
["docker", "history", "--no-trunc", "--format", "{{.CreatedBy}}", "myapp:latest"],
capture_output=True, text=True
)
layers = result.stdout.strip().split("\n")
assert len(layers) <= 20, f"Too many layers: {len(layers)}"
print(f"Layer count: {len(layers)} (limit: 20)")
test_image_size()
test_layer_count()
Practice Questions
1. What is the purpose of container structure tests?
They validate the image content — files, commands, environment variables, ports — without running the container.
2. Why should you use health checks in Docker Compose test files?
Health checks ensure dependent services are ready before the test suite starts, preventing flaky failures from race conditions.
3. What does --abort-on-container-exit do in Docker Compose?
It stops all containers when any single container exits, which is essential for CI pipelines to fail fast.
4. How can you test environment variable propagation in containers?
Use structure tests to check env vars in the image, and integration tests to verify the running container reads them correctly.
Challenge: Create a Docker Compose test stack with three services: a Python Flask API, PostgreSQL database, and Redis cache. Write integration tests covering health check, CRUD operations, and cache invalidation. Run with --abort-on-container-exit.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro