Integration Testing Swift with Docker: Advanced Level

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction

\n

Integration testing is a critical stage of development that verifies the interaction of your Swift application components with external dependencies: databases, APIs, file systems, and network services. However, traditional approaches to integration testing on macOS/iOS often suffer from the "environment problem" — tests that work on a developer's machine may fail on a CI server due to differences in library versions, network settings, or database configurations.

\n

Docker solves this problem radically: you package all dependencies (PostgreSQL, Redis, Mock servers) into isolated containers that run identically on any platform. In this article, we will explore advanced techniques for integration testing Swift with Docker: from setting up a test environment to parallel execution and CI/CD integration.

\n\n

1. Preparing the Test Environment with Docker Compose

\n

Let's start by creating an isolated environment for tests. Instead of running each service manually, we use docker-compose.yml to declaratively describe all dependencies.

\n\n

Example docker-compose.yml for a Swift project

\n
version: '3.8'\nservices:\n  postgres_test:\n    image: postgres:15-alpine\n    environment:\n      POSTGRES_USER: test_user\n      POSTGRES_PASSWORD: test_pass\n      POSTGRES_DB: swift_test_db\n    ports:\n      - "5433:5432"  # Use a non-standard port to avoid conflicts with local DB\n    tmpfs: /var/lib/postgresql/data  # Data in memory — fast cleanup\n\n  redis_test:\n    image: redis:7-alpine\n    ports:\n      - "6380:6379"\n\n  mock_server:\n    build: ./mock-server  # Custom mock server on Vapor\n    ports:\n      - "8081:8080"\n    environment:\n      LOG_LEVEL: debug
\n\n

Swift code for dynamic test configuration

\n

To make tests connect to Docker containers rather than local services, use environment variables:

\n
import XCTest\n\nfinal class IntegrationTests: XCTestCase {\n    var app: XCTestApplication?\n\n    override func setUp() async throws {\n        // Get configuration from environment variables (set in CI or docker-compose)\n        let dbHost = ProcessInfo.processInfo.environment["DB_HOST"] ?? "localhost"\n        let dbPort = Int(ProcessInfo.processInfo.environment["DB_PORT"] ?? "5433") ?? 5433\n        let redisHost = ProcessInfo.processInfo.environment["REDIS_HOST"] ?? "localhost"\n        let mockHost = ProcessInfo.processInfo.environment["MOCK_HOST"] ?? "http://localhost:8081"\n\n        // Configure the test application (e.g., Vapor or Kitura)\n        let config = AppConfig(\n            database: DatabaseConfig(host: dbHost, port: dbPort, \n                                     username: "test_user", password: "test_pass",\n                                     database: "swift_test_db"),\n            redis: RedisConfig(host: redisHost, port: 6380),\n            mockServiceURL: mockHost\n        )\n\n        app = try await XCTestApplication.start(config: config)\n    }\n\n    override func tearDown() async throws {\n        try await app?.shutdown()\n    }\n}
\n\n

2. Advanced Setup: Parallel Execution and Test Isolation

\n

One of the main problems with integration tests is their execution time. Docker allows you to run multiple copies of the test environment in parallel, significantly speeding up the run.

\n\n

Isolation Strategy: One Container per Test Class

\n

Use docker-compose --project-name to create unique instances:

\n
#!/bin/bash\n# Run tests with a unique project-name for parallel execution\nTEST_SUITE=$1\nPROJECT_NAME="swift_test_${TEST_SUITE}_$(date +%s)"\n\ndocker-compose -p $PROJECT_NAME up -d --force-recreate\nsleep 5  # Wait for container initialization\n\n# Run a specific test class\nxcodebuild test -scheme MyApp -destina                

Blogs

Book Recommendations