Тестирование в JavaScript: Unit, Integration, E2E — Полное руководство
Качество кода — залог успеха любого проекта. В мире JavaScript (особенно в Node.js) тестирование стало не просто хорошей практикой, а необходимостью. Разбираем три ключевых уровня: модульные (unit), интеграционные (integration) и сквозные (E2E) тесты. Вы узнаете, чем они отличаются, когда применять каждый тип и увидите рабочие примеры на популярных инструментах.
1. Unit-тестирование: проверяем изолированные модули
Unit-тесты проверяют работу отдельных функций, классов или модулей в изоляции от внешних зависимостей (базы данных, API, файловой системы). Это самый быстрый и надежный уровень.
Инструменты и настройка
Самый популярный фреймворк — Jest. Установка:
npm install --save-dev jest
Добавьте скрипт в package.json:
"scripts": {
"test": "jest"
}
Пример: тестируем функцию расчета скидки
Создадим файл discount.js:
// discount.js
function applyDiscount(price, discountPercent) {
if (price <= 0) throw new Error('Price must be positive');
if (discountPercent < 0 || discountPercent > 100) throw new Error('Invalid discount');
return price - (price * discountPercent) / 100;
}
module.exports = { applyDiscount };
Теперь напишем unit-тест в discount.test.js:
const { applyDiscount } = require('./discount');
describe('applyDiscount', () => {
test('calculates 10% discount correctly', () => {
expect(applyDiscount(100, 10)).toBe(90);
});
test('throws error for negative price', () => {
expect(() => applyDiscount(-10, 10)).toThrow('Price must be positive');
});
test('throws error for invalid discount percent', () => {
expect(() => applyDiscount(100, 150)).toThrow('Invalid discount');
});
});
Запуск: npm test. Jest сам найдет файлы *.test.js.
Совет: Используйте mock-объекты для изоляции от внешних сервисов.
// Пример мока внешнего API
jest.mock('./api');
const api = require('./api');
api.getData.mockResolvedValue({ id: 1 });
2. Интеграционное тестирование: проверяем взаимодействие компонентов
Integration-тесты проверяют, как разные модули работают вместе: база данных + бизнес-логика + HTTP-роуты. Они медленнее unit-тестов, но дают больше уверенности в корректности системы.
Инструменты: Supertest + Jest
Supertest позволяет делать HTTP-запросы к вашему Express-приложению без реального запуска сервера.
npm install --save-dev supertest
Пример: тестируем REST API
Допустим, есть простое Express-приложение app.js:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'Missing fields' });
}
// Сохраняем в БД (упрощенно)
res.status(201).json({ id: 1, name, email });
});
module.exports = app;
Интеграционный тест users.test.js:
const request = require('supertest');
const app = require('./app');
describe('POST /users', () => {
test('creates user with valid data', async () => {
const response = await request(app)
.post('/users')
.send({ name: 'Alice', email: 'alice@test.com' });
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe('Alice');
});
test('returns 400 for missing email', async () => {
const response = await request(app)
.post('/users')
.send({ name: 'Bob' });
expect(response.status).toBe(400);
expect(response.body.error).toBe('Missing fields');
});
});
Важно: Для реальных проектов поднимайте тестовую БД (например, MongoDB Memory Server или SQLite in-memory).
3. E2E-тестирование: проверяем пользовательские сценарии
Сквозные (End-to-End) тесты симулируют действия реального пользователя в браузере. Они самые медленные, но критически важны для проверки критических путей (логин, оформление заказа).
Инструменты: Playwright
Современная альтернатива Selenium. Установка:
npm install --save-dev @playwright/test
npx playwright install
Пример: тест страницы логина
Создадим login.spec.js:
const { test, expect } = require('@playwright/test');
test('successful login redirects to dashboard', async ({ page }) => {
// 1. Открываем страницу логина
await page.goto('https://example.com/login');
// 2. Заполняем форму
await page.fill('input[name="email"]', 'user@test.com');
await page.fill('input[name="password"]', 'password123');
// 3. Кликаем кнопку
await page.click('button[type="submit"]');
// 4. Ждем редиректа и проверяем URL
await expect(page).toHaveURL(/\/dashboard/);
// 5. Проверяем приветствие
await expect(page.locator('h1')).toContainText('Welcome');
});
Запуск: npx playwright test. Playwright поддерживает Chrome, Firefox, Safari и Edge.
Совет: Используйте test.describe для группировки тестов и test.beforeEach для повторяющихся действий (логин перед тестом).
4. Стратегия тестирования: пирамида тестов
Правильная стратегия — пирамида тестов:
- Основание (70-80%) — unit-тесты: быстрые, дешевые, покрывают бизнес-логику.
- Середина (15-20%) — integration-тесты: проверяют взаимодействие с БД, API.
- Вершина (5-10%) — E