Тестирование в JavaScript: Unit, Integration, E2E с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Тестирование в 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

Блоги

Рекомендаций по книгам