使用 Docker 进行 JavaScript 集成测试:高级水平
集成测试是现代 Web 应用程序开发的关键阶段。它允许检查系统不同组件(数据库、缓存、外部 API 和应用程序本身)之间的交互。Docker 使这个过程变得可预测、隔离且可重复。在本文中,我们将探讨使用 Docker 进行 JavaScript (Node.js) 集成测试的高级技术。
为什么在集成测试中使用 Docker?
传统的集成测试面临以下问题:
- 开发环境、CI 环境和生产环境之间的差异。
- 共享数据库中的数据污染。
- 启动依赖项(Redis、PostgreSQL、Kafka)的复杂性。
Docker 通过提供轻量级、隔离的容器解决了这些问题。每个测试都可以启动自己的基础设施,并在完成后销毁它。这保证了结果的清洁性和可重复性。
使用 Docker Compose 配置测试环境
对于高级测试,我们将使用 docker-compose.yml,它描述了测试所需的所有服务:应用程序本身、数据库、缓存和模拟服务器。
示例 docker-compose.test.yml:
version: '3.8'services: app: build: . environment: - NODE_ENV=test - DB_HOST=postgres_test - REDIS_HOST=redis_test - MOCK_SERVER_URL=http://mock-server:8080 depends_on: - postgres_test - redis_test - mock-server command: ["npm", "run", "test:integration"]
postgres_test: image: postgres:15-alpine environment: POSTGRES_DB: testdb POSTGRES_USER: test POSTGRES_PASSWORD: test tmpfs: /var/lib/postgresql/data
redis_test: image: redis:7-alpine tmpfs: /data
mock-server: image: mockserver/mockserver:latest environment: MOCKSERVER_LOG_LEVEL: ERROR关键点:
- tmpfs:数据库和 Redis 数据存储在内存中,从而加快测试速度。
- mock-server:用于模拟外部 API 的隔离服务。
- NODE_ENV=test:将应用程序切换到测试配置。
使用 Testcontainers 编写集成测试
Node.js 的 testcontainers 库允许直接从测试中以编程方式管理容器。这提供了灵活性:您可以为每个测试套件启动特定的容器。
安装:
npm install --save-dev testcontainers使用 PostgreSQL 的测试示例:
const { GenericContainer } = require('testcontainers');const { Client } = require('pg');
describe('User Repository Integration Test', () => { let container; let client;
beforeAll(async () => { // 启动 PostgreSQL 容器 container = await new GenericContainer('postgres:15-alpine') .withEnvironment({ POSTGRES_DB: 'testdb', POSTGRES_USER: 'test', POSTGRES_PASSWORD: 'test' }) .withExposedPorts(5432) .start();
// 连接到容器 client = new Client({ host: container.getHost(), port: container.getMappedPort(5432), database: 'testdb', user: 'test', password: 'test' }); await client.connect();
// 创建模式 await client.query(` CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100), email VARCHAR(100) UNIQUE ) `); });
afterAll(async () => { await client.end(); await container.stop(); });
test('should insert and retrieve user', async () => { await client.query(