Ответ
Мы использовали комбинацию разных уровней тестирования с Jest в качестве основного фреймворка.
1. Unit-тесты:
Тестировали отдельные функции, модули и классы, изолируя их от внешних зависимостей с помощью моков (jest.mock()).
// service/userService.test.js
const userService = require('./userService');
const User = require('../models/User');
jest.mock('../models/User'); // Мокаем модель Mongoose
describe('User Service', () => {
test('createUser should hash password', async () => {
User.mockImplementation(() => ({
save: jest.fn().mockResolvedValue({ _id: '123', email: 'test@mail.com' })
}));
const result = await userService.createUser('test@mail.com', 'plainPassword');
expect(result.email).toBe('test@mail.com');
expect(result.password).not.toBe('plainPassword'); // Проверяем, что пароль захэширован
});
});
2. Интеграционные тесты:
Проверяли взаимодействие нескольких модулей, например, сервиса с реальной (или in-memory) базой данных. Для этого поднимали тестовый экземпляр MongoDB с помощью mongodb-memory-server.
3. API (E2E) тесты: С помощью Supertest тестировали HTTP-эндпоинты нашего Express-приложения.
// tests/api/users.test.js
const request = require('supertest');
const app = require('../../app');
const { generateAuthToken } = require('../../utils/auth');
describe('GET /api/users', () => {
test('should return 401 without token', async () => {
const res = await request(app).get('/api/users');
expect(res.statusCode).toBe(401);
});
test('should return user list for admin', async () => {
const adminToken = generateAuthToken({ userId: '1', role: 'admin' });
const res = await request(app)
.get('/api/users')
.set('Authorization', `Bearer ${adminToken}`);
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body)).toBe(true);
});
});
Инфраструктура и инструменты:
- Husky + lint-staged: Запуск линтера (
ESLint) и юнит-тестов перед коммитом. - Jest coverage: Генерация отчета о покрытии кода тестами (
npm test -- --coverage). - GitHub Actions: Автоматический прогон всей тестовой suites при каждом пуше в PR. Деплой на production происходил только после успешного прохождения всех тестов.