Introduction : pourquoi l’intégration de tests TypeScript avec Docker ?
L’intégration de tests est une étape clé du développement qui vérifie l’interaction entre les différents modules de votre application. Contrairement aux tests unitaires, qui isolent un seul composant, les tests d’intégration vérifient comment fonctionnent ensemble la base de données, l’API, les services externes et la logique métier.
L’utilisation de Docker dans l’intégration de tests TypeScript résout plusieurs problèmes :
- Isolation de l’environnement — les tests s’exécutent dans des conditions identiques sur toutes les machines
- Gestion des dépendances — les bases de données, files d’attente et caches sont démarrés automatiquement
- Reproductibilité — les tests donnent les mêmes résultats localement et dans le CI/CD
- Récupération rapide — les conteneurs sont recréés en quelques secondes
Dans cet article, nous allons détailler un exemple pratique de configuration de tests d’intégration pour une application TypeScript utilisant Docker, Jest et Supertest.
1. Préparation du projet et installation des dépendances
Commençons par créer un projet TypeScript de base. Assurez-vous d’avoir Node.js (v18+) et Docker installés.
mkdir typescript-docker-testingcd typescript-docker-testingnpm init -ynpm install express typescript ts-node @types/node @types/expressnpm install --save-dev jest ts-jest @types/jest supertest @types/supertestCréez tsconfig.json :
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules", "**/*.test.ts"]}Configurez Jest dans package.json :
"jest": { "preset": "ts-jest", "testEnvironment": "node", "testMatch": ["**/*.test.ts"]}2. Création d’une application Express simple
Créons une structure de dossiers et une application simple qui interagira avec une base de données PostgreSQL.
mkdir srcmkdir src/configmkdir src/modelsmkdir src/routesmkdir src/__tests__src/config/database.ts — configuration de la connexion à la base de données :
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 — application principale :
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 — point d’entrée :
import app from './app';
const PORT = process.env.PORT || 3000;app.listen(PORT, () => { console.log(`Server running on port ${PORT}`);});src/routes/users.ts — route simple pour les utilisateurs :
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