TypeScript 与 Docker 集成测试:高级水平
\n\n集成测试是验证系统组件之间交互的关键环节。对于 TypeScript 应用,尤其是微服务架构,Docker 成为不可或缺的工具。在本文中,我们将探讨使用 Docker 配置和执行集成测试的高级技术,这些技术将帮助您提高开发的可靠性和速度。
\n\n1. 为什么在 TypeScript 集成测试中使用 Docker?
\nDocker 可以隔离测试环境,确保其可重复性。您无需手动配置数据库、消息队列和其他依赖项,只需在容器中运行它们。这对于 TypeScript 项目尤为重要,因为类型系统可能会隐藏运行时错误,而这些错误往往在集成时才会暴露。
\n- \n
- 隔离性:每个测试在干净的环境中运行 \n
- 速度:容器在几秒钟内启动 \n
- 并行性:可以同时测试不同版本的依赖项 \n
2. 为测试环境配置 Docker Compose
\n创建一个 docker-compose.test.yml 文件,用于启动 PostgreSQL、Redis 以及测试用的应用本身:
version: '3.8'\nservices:\n db-test:\n image: postgres:15-alpine\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: test\n POSTGRES_PASSWORD: testpass\n ports:\n - "5433:5432"\n tmpfs: /var/lib/postgresql/data\n\n redis-test:\n image: redis:7-alpine\n ports:\n - "6380:6379"\n\n app-test:\n build:\n context: .\n dockerfile: Dockerfile.test\n environment:\n DATABASE_URL: postgres://test:testpass@db-test:5432/testdb\n REDIS_URL: redis://redis-test:6379\n depends_on:\n - db-test\n - redis-test\n command: ["npm", "run", "test:integration"]\n这里我们对数据库使用了 tmpfs,这样数据不会在每次运行之间保留,从而加快测试速度。
3. 使用 TestContainers 进行高级 TypeScript 测试配置
\ntestcontainers 库允许您直接从 TypeScript 代码中管理容器。这提供了灵活性:您可以仅为特定的测试场景启动容器。
安装:
\nnpm install --save-dev testcontainers\n使用动态容器的集成测试示例:
\nimport { GenericContainer, StartedTestContainer } from 'testcontainers';\nimport { Client } from 'pg';\nimport { UserService } from './user-service';\n\nlet container: StartedTestContainer;\nlet client: Client;\n\nbeforeAll(async () => {\n // 启动 PostgreSQL 容器\n container = await new GenericContainer('postgres:15-alpine')\n .withEnvironment({\n POSTGRES_DB: 'test',\n POSTGRES_USER: 'test',\n POSTGRES_PASSWORD: 'test'\n })\n .withExposedPorts(5432)\n .start();\n\n // 连接到测试数据库\n const host = container.getHost();\n const port = container.getMappedPort(5432);\n client = new Client({\n host,\n port,\n database: 'test',\n user: 'test',\n password: 'test'\n });\n await client.connect();\n\n // 执行迁移\n await client.query(`\n CREATE TABLE users (\n id SERIAL PRIMARY KEY,\n email VARCHAR(255) UNIQUE NOT NULL,\n name VARCHAR(255)\n )\n `);\n});\n\nafterAll(async () => {\n await client.end();\n await container.stop();\n});\n\ntest('UserService.createUser 在数据库中创建用户', async () => {\n const userService = new UserService(client);\n const user = await userService.createUser({\n email: 'test@example.com',\n name: 'Test User'\n });\n\n const result = await client.query('SELECT * FROM users WHERE email = $1', ['test@example.com']);\n expect(result.rows[0]).toMatchObject({\n email: 'test@example.com',\n