24. Тестирование с Docker
Тестирование контейнеризованных приложений включает несколько уровней: unit-тесты внутри контейнеров, интеграционные тесты с реальными зависимостями (базой данных, Redis) и end-to-end тесты всего стека.
Запуск тестов в Docker
Заголовок раздела «Запуск тестов в Docker»# Запустить тесты в контейнереdocker run --rm myapp npm test
# С переменными окруженияdocker run --rm \ -e NODE_ENV=test \ -e DATABASE_URL=postgresql://localhost/testdb \ myapp npm test
# Запустить конкретный файл тестовdocker run --rm myapp npx jest src/user.test.js
# С coveragedocker run --rm \ -v $(pwd)/coverage:/app/coverage \ myapp npm run test:coverageMulti-stage тесты в Dockerfile
Заголовок раздела «Multi-stage тесты в Dockerfile»# Dockerfile с этапом тестирования
FROM node:20-alpine AS baseWORKDIR /appCOPY package*.json ./RUN npm ci
FROM base AS testCOPY . .RUN npm test # запустить тесты при сборке # сборка упадёт если тесты не пройдут
FROM base AS productionRUN npm ci --only=productionCOPY --from=test /app/dist ./dist # только из успешного test-этапаCMD ["node", "dist/server.js"]# Запустить только до test-этапаdocker build --target test -t myapp:test .
# Сборка упадёт, если тесты не пройдут!docker build -t myapp:prod .Docker Compose для тестового окружения
Заголовок раздела «Docker Compose для тестового окружения»version: '3.8'services: tests: build: context: . target: test environment: - NODE_ENV=test - DATABASE_URL=postgresql://testuser:testpass@postgres-test/testdb - REDIS_URL=redis://redis-test:6379 depends_on: postgres-test: condition: service_healthy redis-test: condition: service_healthy command: npm run test:ci
postgres-test: image: postgres:15-alpine environment: POSTGRES_DB: testdb POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass healthcheck: test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"] interval: 5s timeout: 3s retries: 5 tmpfs: - /var/lib/postgresql/data # данные в RAM, быстрее
redis-test: image: redis:7-alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 3# Запустить тестыdocker compose -f docker-compose.test.yml up \ --abort-on-container-exit \ --exit-code-from tests
# Очистить после тестовdocker compose -f docker-compose.test.yml down -vTestcontainers
Заголовок раздела «Testcontainers»Testcontainers — библиотека, позволяющая запускать реальные Docker-контейнеры из кода тестов:
// Jest + Testcontainers для Node.jsconst { PostgreSqlContainer } = require('@testcontainers/postgresql');const { GenericContainer } = require('testcontainers');
describe('User Service', () => { let pgContainer; let redisContainer;
beforeAll(async () => { // Запустить реальный PostgreSQL в Docker pgContainer = await new PostgreSqlContainer('postgres:15-alpine') .withDatabase('testdb') .withUsername('testuser') .withPassword('testpass') .start();
// Запустить Redis redisContainer = await new GenericContainer('redis:7-alpine') .withExposedPorts(6379) .start(); });
afterAll(async () => { await pgContainer.stop(); await redisContainer.stop(); });
test('should create user', async () => { const db = await connectToDatabase(pgContainer.getConnectionUri()); const user = await createUser(db, { name: 'Alice' }); expect(user.id).toBeDefined(); });});Параллельные тесты в CI
Заголовок раздела «Параллельные тесты в CI»jobs: test: strategy: matrix: node: [18, 20] postgres: [14, 15] runs-on: ubuntu-latest
services: postgres: image: postgres:${{ matrix.postgres }} env: POSTGRES_PASSWORD: test options: >- --health-cmd pg_isready --health-interval 10s steps: - uses: actions/checkout@v4 - run: docker build --target test -t myapp:test . - run: docker run --rm myapp:test npm test