Files
api-codegen/tests/README.md
2025-10-28 09:58:44 +03:00

10 KiB
Raw Blame History

Документация по тестированию API CodeGen

Обзор

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

  • Юнит тесты - тестирование отдельных модулей
  • Интеграционные тесты - тестирование взаимодействия компонентов
  • E2E тесты - полный цикл от генерации до использования

Общее количество тестов: ~72 кейса

Стек технологий

  • Bun test - встроенный test runner (быстрый, совместим с Jest API)
  • msw - Mock Service Worker для HTTP мокирования
  • tmp - создание временных директорий
  • execa - запуск CLI команд

Структура тестов

tests/
├── fixtures/           # Тестовые OpenAPI спецификации
│   ├── minimal.json   # Минимальная валидная спецификация
│   ├── valid.json     # Полная валидная спецификация
│   ├── complex.json   # Сложная (100+ endpoints)
│   ├── with-auth.json # С authentication
│   ├── invalid.json   # Невалидная спецификация
│   ├── empty.json     # Пустая спецификация
│   └── edge-cases.json # Unicode, спецсимволы
│
├── helpers/           # Вспомогательные функции
│   ├── setup.ts      # Создание/очистка temp директорий
│   ├── mock-server.ts # Mock HTTP сервер
│   └── fixtures.ts   # Утилиты для фикстур
│
├── unit/             # Юнит тесты
│   ├── cli.test.ts          # CLI команды
│   ├── generator.test.ts    # Генератор
│   ├── config.test.ts       # Валидация конфигурации
│   └── utils/
│       └── file.test.ts     # Файловые утилиты
│
└── integration/      # Интеграционные тесты
    ├── e2e-generation.test.ts    # E2E генерация
    └── generated-client.test.ts  # Сгенерированный клиент

Запуск тестов

Все тесты

bun test

Только юнит тесты

bun test:unit

Только интеграционные тесты

bun test:integration

Watch режим

bun test:watch

С coverage

bun test:coverage

Конкретный файл

bun test tests/unit/cli.test.ts

Конкретный тест

bun test -t "should generate client with custom name"

Покрываемые сценарии

1. CLI тесты (15 кейсов)

Базовые сценарии:

  • Запуск с локальным файлом
  • Запуск с URL
  • Генерация с кастомным именем
  • Автоматическое имя из OpenAPI title
  • Отображение версии --version
  • Отображение help --help

Обработка ошибок:

  • Отсутствие --input
  • Отсутствие --output
  • Несуществующий файл
  • Невалидный OpenAPI
  • Недоступный URL
  • Ошибки записи

2. Генератор (20 кейсов)

Корректная генерация:

  • Создание файла
  • Структура кода
  • Все HTTP методы (GET, POST, PUT, PATCH, DELETE)
  • Типы для request/response
  • Path/query параметры
  • Request body
  • Enum типы
  • Bearer authentication
  • Хук onFormatRouteName
  • BaseUrl из servers

Edge cases:

  • Пустая спецификация
  • Минимальная спецификация
  • Сложная спецификация (100+ endpoints)
  • Unicode символы

3. Утилиты (10 кейсов)

file.test.ts:

  • fileExists() - существующий файл
  • fileExists() - несуществующий файл
  • readJsonFile() - локальный файл
  • readJsonFile() - URL
  • readJsonFile() - невалидный JSON
  • readJsonFile() - недоступный URL
  • ensureDir() - создание директорий
  • writeFileWithDirs() - запись с созданием директорий

config.test.ts:

  • Валидная конфигурация
  • Без inputPath
  • Без outputPath
  • Опциональное поле fileName

4. Сгенерированный клиент (7 кейсов)

Компиляция:

  • TypeScript компиляция без ошибок
  • Отсутствие type errors
  • Корректные импорты/экспорты

Корректность API:

  • Все endpoints присутствуют
  • Корректные имена методов
  • HttpClient инициализация
  • Метод setSecurityData

5. Интеграционные E2E (15 кейсов)

Полный цикл:

  • CLI → создание → импорт → использование
  • Генерация из локального файла
  • Генерация из URL
  • Повторная генерация

HTTP с mock:

  • GET без параметров
  • GET с query параметрами
  • POST с body
  • PUT/PATCH/DELETE
  • Статусы 200, 201, 400, 401, 404, 500
  • Network errors
  • Bearer authentication
  • Custom headers

Написание новых тестов

Пример юнит теста

import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
import { setupTest } from '../helpers/setup.js';

describe('My Feature', () => {
  let tempDir: string;
  let cleanup: () => Promise<void>;

  beforeEach(async () => {
    const setup = await setupTest();
    tempDir = setup.tempDir;
    cleanup = setup.cleanup;
  });

  afterEach(async () => {
    await cleanup();
  });

  test('should do something', () => {
    // Arrange
    const input = 'test';
    
    // Act
    const result = myFunction(input);
    
    // Assert
    expect(result).toBe('expected');
  });
});

Пример интеграционного теста

import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { createMockServer } from '../helpers/mock-server.js';

describe('Integration Test', () => {
  let mockServer;

  beforeAll(() => {
    mockServer = createMockServer();
    mockServer.start();
  });

  afterAll(() => {
    mockServer.stop();
  });

  test('should make HTTP request', async () => {
    const response = await fetch('https://api.example.com/users');
    const data = await response.json();
    
    expect(response.status).toBe(200);
    expect(Array.isArray(data)).toBe(true);
  });
});

Лучшие практики

1. Изоляция тестов

  • Каждый тест должен быть независимым
  • Использовать beforeEach/afterEach для setup/cleanup
  • Не полагаться на порядок выполнения

2. Именование

  • Описательные названия: "должен создать файл при корректных параметрах"
  • Группировать с помощью describe
  • Использовать принцип AAA (Arrange, Act, Assert)

3. Очистка ресурсов

  • Всегда очищать временные файлы
  • Закрывать соединения
  • Использовать afterEach для гарантии очистки

4. Async/Await

  • Всегда использовать async/await для асинхронных операций
  • Не забывать await перед промисами
  • Устанавливать таймауты для долгих операций

5. Mock данные

  • Использовать фикстуры для тестовых данных
  • Не хардкодить данные в тестах
  • Переиспользовать тестовые данные

Troubleshooting

Тесты падают с timeout

Увеличьте таймаут для конкретного теста:

test('long running test', async () => {
  // test code
}, 60000); // 60 секунд

Тесты не очищаются

Проверьте что cleanup() вызывается в afterEach:

afterEach(async () => {
  await cleanup();
});

Mock сервер не работает

Убедитесь что:

  1. Сервер запущен в beforeAll
  2. Сервер остановлен в afterAll
  3. Хендлеры правильно настроены

Файлы не находятся

Используйте абсолютные пути или пути относительно __dirname:

const fixturePath = join(__dirname, '../fixtures/test.json');

CI/CD

Тесты автоматически запускаются при:

  • Push в любую ветку
  • Создании Pull Request
  • Перед деплоем

Требования для прохождения CI:

  • Все тесты должны пройти
  • Coverage > 80%
  • Нет TypeScript ошибок
  • Нет lint ошибок

Метрики

Целевые показатели

  • Coverage: > 90%
  • Скорость: < 30 сек для всех тестов
  • Стабильность: 0 flaky тестов

Текущие показатели

Запустите bun test:coverage для просмотра актуальных метрик.

Дополнительная информация