Skip to content
IRC-CodingIRC-Coding
API TestingUnit тестыIntegration тестыContract тестыСтратегия тестированияConsumer Driven Contracts

API Testing: Unit, Integration и Contract тесты

API Testing: Unit тесты, интеграционные тесты, Contract тесты, стратегии и инструменты для надежных API.

S

schutzgeist

5 min read
API Testing: Unit, Integration и Contract тесты

Тестирование API: Unit, интеграционные и контрактные тесты

Надёжные API требуют продуманной стратегии тестирования, которая сочетает unit-тесты, интеграционные тесты и контрактные тесты. Это позволяет выявлять ошибки на ранних этапах и защищать контракты между сервисом и клиентами.

Краткое описание

Тестирование API охватывает все проверки, которые гарантируют корректность, безопасность, производительность и стабильность интерфейса. Unit-тесты проверяют изолированные функции, контроллеры или обработчики без внешних зависимостей. Интеграционные тесты проверяют взаимодействие нескольких компонентов: API, базы данных, внешних сервисов. Контрактные тесты гарантируют, что поставщик и потребитель API соблюдают одинаковый контракт, например через OpenAPI или Pact. Хорошая стратегия покрывает API на разных уровнях, полностью автоматизирована и работает в конвейере Continuous Integration. Цель состоит в раннем обнаружении ошибок, предотвращении регрессий и надёжной документации контракта между API и клиентами.

Основные компоненты

Unit-тесты для API

Unit-тесты проверяют небольшие изолированные единицы API: обработчики, контроллеры, логику валидации или маппинга. Внешние зависимости, такие как базы данных или HTTP-клиенты, заменяются на mock-объекты или заглушки. Unit-тесты работают быстро и дают оперативную обратную связь при изменениях кода.

Интеграционные тесты

Интеграционные тесты проверяют взаимодействие API с реальными или контейнеризованными зависимостями. Сюда входят обращения к базе данных, очереди сообщений, внешние API и сервисы аутентификации. Testcontainers позволяют запускать базы данных и другие сервисы в тестовой среде.

End-to-End тесты

End-to-End тесты имитируют работу API со стороны клиента. Они отправляют реальные HTTP-запросы и проверяют полный ответ. Часто используются инструменты как Postman, REST Assured или Supertest. E2E тесты работают медленнее, но охватывают весь стек приложения.

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

Контрактные тесты проверяют, соблюдают ли API и клиент оговорённый контракт. Контракт может быть определён через OpenAPI, JSON Schema или фреймворки вроде Pact. Consumer Driven Contracts позволяют клиентам сообщать свои ожидания от поставщика.

Consumer Driven Contracts

При использовании Consumer Driven Contracts клиенты описывают свои ожидания как контракт. Поставщик должен выполнить этот контракт. Pact является популярным фреймворком для этого подхода. Он предотвращает непредвиденное нарушение клиентов при изменениях API.

Тестовая пирамида

Тестовая пирамида говорит: нужно иметь много быстрых unit-тестов, меньше интеграционных тестов и лишь несколько медленных E2E тестов. Контрактные тесты дополняют пирамиду между интеграционным и unit-уровнем. Они помогают эффективно проверять контракты интерфейсов.

Тестовые данные и fixtures

Тестовые данные должны быть воспроизводимыми и изолированными. Fixtures, фабрики или методы инициализации создают необходимые данные перед каждым тестом. Тесты с базой данных должны использовать транзакции или свежие копии БД, чтобы состояния между тестами не пересекались.

Mocking и Stubbing

Mocking заменяет внешние зависимости контролируемыми объектами. Stubbing предоставляет заранее определённые ответы. Обе техники важны для unit-тестов, но не нужны для интеграционных тестов, где используются реальные зависимости.

Fuzzing и negative-тесты

Negative-тесты проверяют, как API обрабатывает некорректные входные данные, пропущенные поля или неожиданные типы данных. Fuzzing автоматически генерирует множество случайных или полусхематичных входных данных для поиска уязвимостей.

Performance-тесты

Performance-тесты проверяют время ответа, пропускную способность и поведение под нагрузкой. Используются инструменты вроде k6, JMeter или Gatling. Они дополняют функциональные тесты и важны для API с высокими требованиями к доступности и масштабируемости.

Интеграция с CI/CD

API-тесты должны автоматически запускаться в конвейере Continuous Integration. Unit-тесты запускаются при каждой сборке, интеграционные тесты перед слиянием, контрактные тесты при изменениях API, E2E тесты перед развёртыванием. Ошибки останавливают сборку на раннем этапе.

Практический пример

Команда на Node.js тестирует API заказов на всех уровнях.

Unit-тест валидации заказа:

describe('Order validation', () => {
  test('rejects negative quantity', () => {
    const result = validateOrder({ customerId: 1, items: [{ productId: 5, quantity: -1 }] });
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('quantity must be positive');
  });
});

Интеграционный тест с Testcontainers:

describe('POST /orders', () => {
  test('creates an order and persists it', async () => {
    const response = await request(app)
      .post('/orders')
      .send({ customerId: 1, items: [{ productId: 5, quantity: 2 }] })
      .expect(201);

    expect(response.body.id).toBeDefined();
    expect(response.body.status).toBe('created');

    const order = await db.query('SELECT * FROM orders WHERE id = ?', [response.body.id]);
    expect(order).toHaveLength(1);
  });
});

Контрактный тест с Pact:

const pact = new Pact({
  consumer: 'web-shop',
  provider: 'order-service',
});

await pact.addInteraction({
  state: 'order can be created',
  uponReceiving: 'a request to create an order',
  withRequest: {
    method: 'POST',
    path: '/orders',
    body: { customerId: 1, items: [{ productId: 5, quantity: 2 }] }
  },
  willRespondWith: {
    status: 201,
    body: { id: 1, status: 'created' }
  }
});

Сочетание трёх уровней обеспечивает полную и своевременную проверку API.

FAQ: тестирование API

1. Что такое тестирование API?

Тестирование API охватывает все проверки, которые гарантируют корректность, безопасность, производительность и стабильность интерфейса. Оно включает unit-тесты, интеграционные тесты, контрактные тесты и end-to-end тесты.

2. Что такое unit-тест для API?

Unit-тест для API проверяет изолированные функции вроде обработчиков, контроллеров или логики валидации. Внешние зависимости заменяются mock-объектами.

3. Что такое интеграционный тест?

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

4. Что такое контрактный тест?

Контрактный тест гарантирует, что поставщик и потребитель API соблюдают оговорённый контракт. Контракт можно определить через OpenAPI, JSON Schema или Pact.

5. Что такое Consumer Driven Contract Testing?

Consumer Driven Contract Testing означает, что клиенты определяют свои ожидания от API как контракт. Поставщик должен выполнить эти контракты, чтобы предотвратить незамеченные breaking changes.

6. Что такое Pact?

Pact является фреймворком для Consumer Driven Contract Testing. Он генерирует контракты из тестов потребителя и позже проверяет их против поставщика.

7. Что такое тестовая пирамида?

Тестовая пирамида гласит: нужно иметь много быстрых unit-тестов, меньше интеграционных тестов и лишь несколько медленных E2E тестов. Контрактные тесты дополняют пирамиду между unit и интеграционным уровнем.

8. Что такое mocking?

Mocking заменяет внешние зависимости контролируемыми объектами, которые предоставляют заранее определённые ответы. В основном используется в unit-тестах.

9. Что такое Testcontainers?

Testcontainers это контейнеризованные зависимости вроде баз данных, очередей сообщений или кэшей, которые запускаются во время тестов. Они позволяют реалистичные интеграционные тесты без ручной настройки инфраструктуры.

10. Что такое end-to-end тест?

End-to-end тест отправляет реальные HTTP-запросы к API и проверяет полный ответ. Он охватывает весь стек приложения, но работает медленнее и требует больше обслуживания, чем unit-тесты.

11. Что такое negative-тесты?

Negative-тесты проверяют поведение API при некорректных или неполных входных данных. Они гарантируют, что ошибки обрабатываются правильно.

12. Что такое fuzzing?

Fuzzing автоматически генерирует множество случайных или полусхематичных входных данных для поиска уязвимостей, сбоев или неожиданного поведения в API.

13. Что такое performance-тесты для API?

Performance-тесты проверяют время ответа, пропускную способность и поведение под нагрузкой. Инструменты вроде k6, JMeter или Gatling помогают выявить узкие места.

14. Почему API-тесты должны запускаться в CI/CD?

Автоматизированные тесты в CI/CD выявляют ошибки на ранних этапах, до развёртывания в продакшене. Они защищают рефакторинги, предотвращают регрессии и обеспечивают постоянное качество.

15. Какие best practices для тестирования API?

Best practices включают сбалансированную тестовую пирамиду, изолированные и воспроизводимые тестовые данные, чёткое разделение ответственности между уровнями тестирования, контрактные тесты для интерфейсов, автоматизированное выполнение в CI/CD и регулярные performance-тесты.

Продолжаем обучение API

Следующий материал в нашем цикле посвящен реализации API Rate Limiting — разберемся, как внедрить Rate Limiting с использованием Token Bucket, Sliding Window и Redis.

Источники

  1. https://martinfowler.com/articles/consumerDrivenContracts.html
  2. https://docs.pact.io/
  3. https://www.testcontainers.org/

Рекомендуемые книги по тестированию и дизайну API

Если ты хочешь глубже погрузиться в API Testing, автоматизацию тестов и качество ПО, вот подборка полезных книг:

Keine Bücher für Kategorie "api-development" gefunden.

Назад к блогу
Share:

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