引言:为什么需要 TypeScript 与 Docker 的集成测试?
集成测试是开发中的关键阶段,用于验证应用程序不同模块之间的交互。与隔离单个组件的单元测试不同,集成测试检查数据库、API、外部服务和业务逻辑如何协同工作。
在 TypeScript 集成测试中使用 Docker 可以解决以下几个问题:
- 环境隔离 — 测试在所有机器上的相同条件下运行
- 依赖管理 — 数据库、队列和缓存会自动启动
- 可复现性 — 测试在本地和 CI/CD 环境中产生相同的结果
- 快速恢复 — 容器可以在几秒钟内重建
在本文中,我们将通过一个实际示例,讲解如何使用 Docker、Jest 和 Supertest 配置 TypeScript 应用程序的集成测试。
1. 项目准备与依赖安装
首先创建一个基础的 TypeScript 项目。请确保您已安装 Node.js (v18+) 和 Docker。
mkdir typescript-docker-testing
cd typescript-docker-testing
npm init -y
npm install express typescript ts-node @types/node @types/express
npm install --save-dev jest ts-jest @types/jest supertest @types/supertest
创建 tsconfig.json 文件:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.test.ts"]
}
在 package.json 中配置 Jest:
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"testMatch": ["**/*.test.ts"]
}
2. 创建简单的 Express 应用程序
创建文件夹结构和一个将与 PostgreSQL 数据库交互的简单应用程序。
mkdir src
mkdir src/config
mkdir src/models
mkdir src/routes
mkdir src/__tests__
src/config/database.ts — 数据库连接配置:
import { Pool } from 'pg';
const pool = new Pool({
host: process.env.DB_HOST || 'localhost',
port: Number(process.env.DB_PORT) || 5432,
database: process.env.DB_NAME || 'testdb',
user: process.env.DB_USER || 'testuser',
password: process.env.DB_PASSWORD || 'testpass'
});
export default pool;
src/app.ts — 主应用程序:
import express from 'express';
import userRoutes from './routes/users';
const app = express();
app.use(express.json());
app.use('/api/users', userRoutes);
export default app;
src/index.ts — 入口文件:
import app from './app';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
src/routes/users.ts — 简单的用户路由:
import { Router, Request, Response } from 'express';
import pool from '../config/database';
const router = Router();
router.get('/', async (req: Request, res: Response) => {
try {
const result = await pool.query('SELECT * FROM users');
res.json(result.rows);
} catch (error) {
res.status(500).json({ error: 'Database error' });
}
});
router.post('/', async (req: Request, res: Response) => {
const { name, email } = req.body;
try {
const result = await pool.query(
'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
[name, email]
);
res.status(201).json(result.r
```