TypeScript 与 Docker 集成测试:高级水平
集成测试是现代 TypeScript 应用程序开发中的关键阶段。当您的系统由多个微服务、数据库、消息队列和外部 API 组成时,孤立的单元测试已无法覆盖真实的交互场景。Docker 允许创建可重现、隔离的测试环境,使其接近生产环境。在本文中,我们将探讨使用 Docker 进行 TypeScript 应用程序集成测试的高级技术:从容器配置到构建 CI/CD 流水线。
为什么 Docker 是 TypeScript 集成测试的理想工具
传统的集成测试方法常常面临环境问题:“在我的机器上能运行”。Docker 通过提供以下特性解决了这个问题:
- 隔离性 — 每个测试在干净的容器中运行,不受其他进程影响
- 可重现性 — 在所有阶段(本地、CI、staging)提供相同的环境
- 速度 — 轻量级容器可在数秒内启动
- 灵活性 — 轻松组合不同版本的数据库、缓存、队列
对于 TypeScript 项目,Docker 尤其有用,因为它不仅可以测试 Node.js 运行时,还可以测试与 TypeScript 编译器、转译和构建过程的交互。
为 TypeScript 测试配置 Docker 环境
我们从基本配置开始。创建一个用于生产构建的 Dockerfile 和一个单独的用于测试的 Dockerfile:
# Dockerfile.testFROM node:18-alpine AS builder
WORKDIR /appCOPY package*.json ./RUN npm ciCOPY tsconfig.json ./COPY src/ ./src/
# 构建 TypeScriptRUN npm run build
# 测试阶段FROM node:18-alpine AS test-runnerWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package.json ./COPY tests/ ./tests/COPY jest.config.ts ./
# 运行集成测试CMD ["npx", "jest", "--config", "jest.config.ts", "--testMatch", "**/*.integration.test.ts"]为了管理多个服务,我们使用 docker-compose.yml:
version: '3.8'services: app: build: context: . dockerfile: Dockerfile.test depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: - DB_HOST=postgres - DB_PORT=5432 - REDIS_HOST=redis - REDIS_PORT=6379 volumes: - ./tests:/app/tests:ro networks: - test-network
postgres: 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: 5s retries: 5 networks: - test-network
redis: image: redis:7-alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 networks: - test-network
networks: test-network: driver: bridge编写高级 TypeScript 集成测试
现在,我们创建一个测试,验证完整场景:写入数据库、缓存到 Redis,以及将事件发送到队列。使用 testcontainers 库从 TypeScript 代码动态管理容器:
// tests/integration/user-registration.integration.test.tsimport { GenericContainer, StartedTestContainer, Wait } from 'testcontainers';import { PostgreSqlContainer } from '@testcontainers/postgresql';import { RedisContainer } from '@testcontainers/redis';import axi