PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Как внедрить тесты в проект, где их никогда не было: пошаговая стратегия

    Как внедрить тесты в проект, где их никогда не было: пошаговая стратегия

    Аватар автора Как внедрить тесты в проект, где их никогда не было: пошаговая стратегия

    Антон Ларичев

    Иконка календаря14 апреля 2026
    testingjavascripttypescriptmiddleИконка уровня middle
    Картинка поста Как внедрить тесты в проект, где их никогда не было: пошаговая стратегия

    Введение

    Внедрить тесты в проект, где их никогда не было, — одна из самых частых задач для middle-разработчика. Вы приходите на проект, видите тысячи строк кода без единого теста и задаётесь вопросом: с чего вообще начать тестирование legacy-кода? Попытка покрыть всё разом приводит к выгоранию и заброшенным тестам.

    В этой статье разберём пошаговую стратегию внедрения тестов в существующий проект на JavaScript или TypeScript. Без фанатизма, без переписывания всего кода — только практичный подход, который работает в реальных командах.

    Почему нельзя просто взять и покрыть всё тестами

    Первый порыв — написать тесты на всё сразу. Это ошибка. В проекте без тестов код, как правило, тесно связан: функции зависят друг от друга, модули напрямую обращаются к базе данных, конфигурация вшита в бизнес-логику. Такой код сложно тестировать без рефакторинга.

    Вместо этого нужна стратегия тестирования, которая даёт результат с первого дня и постепенно наращивает покрытие.

    Шаг 1: настройка инфраструктуры тестирования

    Прежде чем писать первый тест, подготовьте окружение. Для JavaScript и TypeScript проектов Vitest — оптимальный выбор: быстрый, совместимый с ESM, минимальная настройка.

    Установка и конфигурация Vitest

    npm install -D vitest
    

    Добавьте конфигурацию в корень проекта:

    // vitest.config.ts
    import { defineConfig } from 'vitest/config';
    
    export default defineConfig({
      test: {
        globals: true,
        environment: 'node',
        coverage: {
          provider: 'v8',
          reporter: ['text', 'html'],
          // Не ставьте порог покрытия сразу — он будет расти постепенно
        },
      },
    });
    

    Добавьте скрипты в package.json:

    {
      "scripts": {
        "test": "vitest",
        "test:run": "vitest run",
        "test:coverage": "vitest run --coverage"
      }
    }
    

    Настройте CI-пайплайн так, чтобы тесты запускались на каждый пуш. Даже если тестов пока один — пайплайн должен работать с самого начала.

    Шаг 2: определить критические зоны для первых тестов

    Не пишите тесты на всё подряд. Начните с кода, который ломается чаще всего или несёт наибольшие бизнес-риски.

    Как выбрать, что тестировать первым

    Проанализируйте проект по трём критериям:

    • Частота багов — посмотрите историю коммитов и тикетов. Модули с частыми фиксами — кандидаты номер один.
    • Бизнес-критичность — оплата, регистрация, авторизация. Ошибка здесь стоит дороже всего.
    • Частота изменений — код, который меняется каждую неделю, нуждается в защите от регрессий.
    # Найти файлы с наибольшим количеством коммитов
    git log --pretty=format: --name-only | sort | uniq -c | sort -rn | head -20
    

    Эта команда покажет файлы, которые менялись чаще всего — именно с них стоит начать покрытие тестами.

    Шаг 3: написать первые unit-тесты для чистых функций

    В любом проекте есть функции, которые принимают данные и возвращают результат без побочных эффектов. Валидаторы, форматтеры, калькуляторы, парсеры — это идеальные кандидаты для первых unit-тестов.

    // src/utils/price.ts
    export function formatPrice(amount: number, currency: string = 'RUB'): string {
      if (amount < 0) throw new Error('Сумма не может быть отрицательной');
      return new Intl.NumberFormat('ru-RU', {
        style: 'currency',
        currency,
      }).format(amount);
    }
    
    export function calculateDiscount(price: number, percent: number): number {
      if (percent < 0 || percent > 100) {
        throw new Error('Процент скидки должен быть от 0 до 100');
      }
      return Math.round(price * (1 - percent / 100));
    }
    

    Тесты для этих функций:

    // src/utils/price.test.ts
    import { describe, it, expect } from 'vitest';
    import { formatPrice, calculateDiscount } from './price';
    
    describe('formatPrice', () => {
      it('форматирует цену в рублях', () => {
        const result = formatPrice(1500);
        expect(result).toContain('1');
        expect(result).toContain('500');
      });
    
      it('выбрасывает ошибку для отрицательной суммы', () => {
        expect(() => formatPrice(-100)).toThrow('Сумма не может быть отрицательной');
      });
    });
    
    describe('calculateDiscount', () => {
      it('рассчитывает скидку 20%', () => {
        expect(calculateDiscount(1000, 20)).toBe(800);
      });
    
      it('возвращает полную цену при скидке 0%', () => {
        expect(calculateDiscount(500, 0)).toBe(500);
      });
    
      it('отклоняет невалидный процент', () => {
        expect(() => calculateDiscount(100, 150)).toThrow();
      });
    });
    

    Такие тесты пишутся за минуты, не требуют рефакторинга основного кода и сразу дают уверенность в корректности.

    Шаг 4: добавить интеграционные тесты для критичных сценариев

    После unit-тестов переходите к интеграционным. Они проверяют взаимодействие модулей — например, что сервис корректно вызывает репозиторий и обрабатывает результат.

    Для изоляции внешних зависимостей используйте моки Vitest:

    // src/services/order.test.ts
    import { describe, it, expect, vi } from 'vitest';
    import { OrderService } from './order.service';
    import { OrderRepository } from '../repositories/order.repository';
    
    // Мокаем модуль репозитория
    vi.mock('../repositories/order.repository');
    
    describe('OrderService', () => {
      it('создаёт заказ и возвращает его ID', async () => {
        // Настраиваем мок
        const mockCreate = vi.fn().mockResolvedValue({ id: 42, status: 'created' });
        vi.mocked(OrderRepository).mockImplementation(() => ({
          create: mockCreate,
        }) as any);
    
        const service = new OrderService(new OrderRepository());
        const result = await service.createOrder({ productId: 1, quantity: 2 });
    
        expect(result.id).toBe(42);
        expect(mockCreate).toHaveBeenCalledWith({
          productId: 1,
          quantity: 2,
        });
      });
    });
    

    Шаг 5: внедрить правило — новый код только с тестами

    Самый важный шаг в стратегии тестирования. Договоритесь с командой: любой новый код или исправление бага сопровождается тестом. Это правило не требует покрывать старый код, но гарантирует, что покрытие растёт с каждым коммитом.

    Добавьте проверку в CI:

    # .github/workflows/test.yml
    name: Tests
    on: [push, pull_request]
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: 20
          - run: npm ci
          - run: npm run test:run
    

    Когда тесты блокируют мёрж, команда быстро привыкает писать их.

    Шаг 6: постепенно повышать покрытие тестами

    После того как инфраструктура работает и новый код пишется с тестами, начинайте наращивать покрытие старого кода. Используйте отчёт coverage для поиска непокрытых участков:

    npm run test:coverage
    

    Установите начальный порог покрытия чуть выше текущего уровня и повышайте его каждый спринт:

    // vitest.config.ts
    coverage: {
      thresholds: {
        statements: 30, // Начните с реального значения
        branches: 25,
        functions: 30,
        lines: 30,
      },
    }
    

    Каждые две недели увеличивайте пороги на 3-5%. Через полгода покрытие вырастет до приемлемого уровня без стресса для команды.

    Частые ошибки при внедрении тестов в legacy-проект

    Попытка покрыть всё за спринт. Это приводит к сотням хрупких тестов, которые ломаются при каждом изменении. Внедряйте тесты постепенно.

    Тестирование деталей реализации. Тест, который проверяет порядок вызовов приватных методов, сломается при любом рефакторинге. Тестируйте поведение, а не реализацию.

    Игнорирование негативных сценариев. Тесты только на happy path дают ложную уверенность. Проверяйте невалидные данные, ошибки сети, пустые ответы.

    Отсутствие тестов в CI. Тесты, которые запускаются только локально, со временем перестают запускаться вообще. CI — обязательное условие.

    Заключение

    Внедрить тесты в проект без тестов — задача не на один день, а долгосрочная стратегия. Начните с настройки Vitest и CI-пайплайна. Напишите первые тесты для чистых функций и критичной бизнес-логики. Введите правило: новый код идёт только с тестами. Постепенно повышайте порог покрытия. Через несколько месяцев вы получите проект, в котором тесты — не обуза, а надёжная страховка от регрессий при каждом релизе.

    Иконка глаза343

    Комментарии

    0

    Постройте личный план изучения Основы Git до уровня Middle — бесплатно!

    Основы Git — часть карты развития Frontend, Backend, DevOps

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Продвинутый JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    TypeScript с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Микрофронтенды и Module Federation: когда применять и как внедрить
    Иконка аватараАнтон
    Иконка календаря28 мая 2026
    микрофронтендыmodule federationwebpack+ 2seniorИконка уровня senior

    Микрофронтенды и Module Federation: когда применять и как внедрить

    Микрофронтенды и Module Federation: разбираем когда нужна такая архитектура, как настроить host и remote приложения и избежать типичных ошибок.

    Иконка чипа0
    Иконка глаза75
    Иконка комментариев0
    Картинка поста Webpack vs Vite в 2025: что выбрать для нового проекта
    Иконка аватараАнтон
    Иконка календаря23 мая 2026
    webpackvitefrontend+ 2middleИконка уровня middle

    Webpack vs Vite в 2025: что выбрать для нового проекта

    Сравнение Webpack и Vite в 2025 году: скорость сборки, конфигурация, HMR, экосистема. Что выбрать для нового проекта и почему.

    Иконка чипа0
    Иконка глаза130
    Иконка комментариев0
    Картинка поста Как стать frontend-разработчиком в 2025: дорожная карта
    Иконка аватараАнтон
    Иконка календаря10 мая 2026
    frontendкарьераjavascript+ 2juniorИконка уровня junior

    Как стать frontend-разработчиком в 2025: дорожная карта

    Дорожная карта frontend-разработчика 2025: какие технологии учить, в каком порядке и как собрать портфолио для первой работы.

    Иконка чипа0
    Иконка глаза304
    Иконка комментариев1
    Иконка чипа0