PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • 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 Собеседование
    • 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-пайплайна. Напишите первые тесты для чистых функций и критичной бизнес-логики. Введите правило: новый код идёт только с тестами. Постепенно повышайте порог покрытия. Через несколько месяцев вы получите проект, в котором тесты — не обуза, а надёжная страховка от регрессий при каждом релизе.

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

    Комментарии

    0

    Постройте личный план изучения Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid до уровня Middle — бесплатно!

    Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid — часть карты развития Frontend

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

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

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

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

    Vue 3 и Pinia

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

    Nuxt

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

    Feature-Sliced Design

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

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

    Картинка поста GraphQL vs REST: что выбрать для API в 2026 году
    Иконка аватараАнтон
    Иконка календаря11 июля 2026
    graphqlrestapi+ 3middleИконка уровня middle

    GraphQL vs REST: что выбрать для API в 2026 году

    GraphQL vs REST — разбираем ключевые отличия, сценарии применения и подводные камни каждого подхода, чтобы выбрать правильный инструмент для вашего проекта.

    Иконка чипа0
    Иконка глаза121
    Иконка комментариев0
    Картинка поста Тестирование React-компонентов с React Testing Library
    Иконка аватараАнтон
    Иконка календаря07 июля 2026
    reacttestingreact-testing-library+ 2middleИконка уровня middle

    Тестирование React-компонентов с React Testing Library

    React Testing Library — инструмент для тестирования React-компонентов через поведение пользователя, а не детали реализации. Примеры, паттерны, частые ошибки.

    Иконка чипа0
    Иконка глаза186
    Иконка комментариев0
    Картинка поста Clean Architecture: чистая архитектура для веб-разработки
    Иконка аватараАнтон
    Иконка календаря02 июля 2026
    архитектураclean architecturetypescript+ 3middleИконка уровня middle

    Clean Architecture: чистая архитектура для веб-разработки

    Clean Architecture разделяет код на независимые слои: бизнес-логика не зависит от фреймворков, БД и внешних сервисов. Разбираем на примерах TypeScript.

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