Тестирование API с Cypress — пошаговое руководство

Cypress — популярный фреймворк для тестирования приложений на JavaScript. Хотя он изначально ориентирован на тестирование UI и взаимодействия в браузере, Cypress отлично подходит и для тестирования API. Фреймворк умеет отправлять HTTP-запросы и валидировать ответы, что делает его удобным инструментом для автоматизации тестов RESTful API.
Кратко: Cypress позволяет писать полные тесты, охватывающие рабочие сценарии приложения, включая взаимодействие фронтенда и бэкенда.
Зачем использовать Cypress для тестирования API
Пара причин выбора Cypress для API тестирования:
- Простая интеграция с экосистемой JavaScript/Node.js.
- Удобный синтаксис и встроенные команды, например cy.request.
- Возможность комбинировать UI- и API-тесты в одном запуске.
Определение: cy.request — встроенная команда Cypress для выполнения HTTP-запросов к серверу и проверки ответов.
Важно: Cypress использует Node.js для выполнения запросов, поэтому тесты выполняются вне браузерной песочницы и работают напрямую с сервером.
План статьи
- Создаём demo Express API
- Пишем контроллеры и роуты
- Настраиваем Cypress
- Пишем реальные тесты с cy.request
- Критерии приёмки и тест-кейсы
- Чек-листы для ролей
- Альтернативы и когда Cypress может не подойти
- Методология и рекомендации для CI/CD
Создание простого Express.js REST API
В этом разделе мы создадим демонстрационный сервер на Express и добавим три маршрута: регистрация, список пользователей и логин. Для простоты данные хранятся в массиве в оперативной памяти.
Установите зависимости проекта (локально в каталоге проекта):
npm install corsУстановите Cypress как dev-зависимость:
npm install cypress --save-devДобавьте npm-скрипт для запуска Cypress в package.json:
"test": "npx cypress open"Контроллеры API
Создайте файл controllers/userControllers.js и добавьте код для регистрации, получения списка пользователей и логина.
const users = [];
exports.registerUser = async (req, res) => {
const { username, password } = req.body;
try {
const newUser = { username, password };
users.push(newUser);
res.status(201).send({ message: 'User registered successfully' });
} catch (error) {
console.error(error);
res.status(500).send({ message: 'An error occurred!!' });
}
};
exports.getUsers = async (req, res) => {
try {
res.json(users);
} catch (error) {
console.error(error);
res.status(500).send({ message: 'An error occurred!!' });
}
};
exports.loginUser = async (req, res) => {
const { username, password } = req.body;
try {
const user = users.find((u) =>
u.username === username && u.password === password);
if (user) {
res.status(200).send({ message: 'Login successful' });
} else {
res.status(401).send({ message: 'Invalid credentials' });
}
} catch (error) {
console.error(error);
res.status(500).send({ message: 'An error occurred!!' });
}
};Пояснение: для реального приложения замените массив users на базу данных и храните пароли в хешированном виде.
Маршруты
Создайте routes/userRoutes.js с определением маршрутов:
const express = require('express');
const router = express.Router();
const userControllers = require('../controllers/userControllers');
const baseURL = '/v1/api/';
router.post(baseURL + 'register', userControllers.registerUser);
router.get(baseURL + 'users', userControllers.getUsers);
router.post(baseURL + 'login', userControllers.loginUser);
module.exports = router;Файл server.js
Обновите server.js, чтобы поднять сервер на порту 5000:
const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
const userRoutes = require('./routes/userRoutes');
app.use('/', userRoutes);
app.listen(port, () => {
console.log(`Server is listening at http://localhost:${port}`);
});
module.exports = app;Совет: для разработки используйте nodemon для автоматического перезапуска сервера при изменениях.
Настройка окружения для тестов
Запустите сервер разработки в одном терминале:
node server.jsВ другом терминале запустите тесты Cypress:
npm run testЭто откроет десктоп-клиент Cypress. На клиенте выберите E2E Testing, затем Continue, чтобы добавить конфигурационные файлы.
После установки в проекте появится папка cypress и файл cypress.config.js. Обновите cypress.config.js, указав базовый URL сервера:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
chromeWebSecurity: false,
e2e: {
baseUrl: 'http://localhost:5000',
setupNodeEvents(on, config) {
},
},
});Объяснение: baseUrl позволяет в тестах указывать относительные URL вместо полного адреса.
Подготовка фикстур и выбор браузера
Выберите браузер в UI Cypress перед запуском тестов (Cypress поддерживает Chrome, Edge, Electron и Firefox).
Создайте фикстуру cypress/fixtures/example.json с тестовыми данными:
{
"username": "testuser",
"password": "password123"
}Фикстуры — это статические тестовые данные, которые удобно переиспользовать в нескольких тестах.
Примеры тестов: cy.request
Cypress предоставляет cy.request для выполнения HTTP-запросов (GET, POST, PUT, DELETE). Ниже — пример полного файла тестов cypress/e2e/user.routes.spec.cy.js.
describe('User Routes', () => {
it('registers a new user', () => {
cy.fixture('example').then((testUser) => {
cy.request({
method: 'POST',
url: `${baseUrl}/v1/api/register`,
body: testUser,
}).then((response) => {
expect(response.status).to.eq(201);
expect(response.body.message).to.eq('User registered successfully');
});
});
});
it('gets users data and the username matches test data', () => {
cy.fixture('example').then((expectedUserData) => {
cy.request({
method: 'GET',
url: `${baseUrl}/v1/api/users`,
}).then((response) => {
expect(response.status).to.eq(200);
const username = response.body[0].username;
expect(username).to.eq(expectedUserData.username);
});
});
});
it('logs in a user', () => {
cy.fixture('example').then((loginData) => {
cy.request({
method: 'POST',
url: `${baseUrl}/v1/api/login`,
body: loginData,
}).then((response) => {
expect(response.status).to.eq(200);
});
});
});
});Примечание: в примерах используется переменная baseUrl. В реальном проекте вместо неё можно использовать относительные пути, если настроен baseUrl в cypress.config.js, например:
cy.request('POST', '/v1/api/register', testUser)Это сокращает код и делает конфигурацию централизованной.
Критерии приёмки для API тестов
Критерии приёмки (на уровне тесткейса):
- Регистрация: ответ 201 и сообщение подтверждения.
- Получение списка: ответ 200 и соответствие username из фикстуры.
- Логин: ответ 200 при корректных данных, 401 при неверных.
- Поведение при ошибках: ответ 500 при непредвиденной ошибке.
- Идентификация повторных регистраций: при попытке повторной регистрации — предусмотреть поведение и покрыть тестом.
Критерии качества тестов:
- Тесты детерминированы и не зависят от внешних сервисов.
- Используются фикстуры и моки для стабилизации данных.
- Тесты выполняются в CI и завершают процесс сборки при падении критичных сценариев.
Тест-кейсы и критерии приёмки (пример таблицы)
| Тест | Ожидаемый статус | Критерий приёмки |
|---|---|---|
| POST /v1/api/register с валидными данными | 201 | Ответ содержит message: ‘User registered successfully’ |
| GET /v1/api/users после регистрации | 200 | Первый пользователь соответствует фикстуре |
| POST /v1/api/login с валидными данными | 200 | Ответ содержит message: ‘Login successful’ |
| POST /v1/api/login с неверным паролем | 401 | Ответ содержит message: ‘Invalid credentials’ |
Чек-листы для ролей
Разделённые по ролям списки задач для успешного API-тестирования.
Developer:
- Покрыть основные сценарии регистрации, получения пользователей, логина.
- Обрабатывать ошибки и возвращать корректные HTTP-коды.
- Хешировать пароли при использовании реальной БД.
- Добавить логирование и метрики ошибок.
QA инженер:
- Написать позитивные и негативные тесты.
- Прогнать тесты в локальной среде и в CI.
- Проверить сценарии повторной регистрации и граничные значения.
- Добавить тесты на валидацию входных данных.
DevOps:
- Интегрировать запуск Cypress в пайплайн CI (headless режим).
- Обеспечить изолированную среду для тестов (контейнеры или ephemeral окружение).
- Настроить ретраи/перезапуск для флейки-тестов.
Security engineer:
- Проверить хранение секретов и передачу паролей по HTTPS.
- Добавить тесты на авторизацию и доступ к приватным ресурсам.
Методология и мини-план тестирования API
- Подготовка окружения: поднять минимально необходимый стек (API + зависимости).
- Фикстуры и тестовые данные: центральное хранилище тестовых наборов.
- Unit тесты контроллеров и бизнес-логики (Jest/Mocha).
- Интеграционные API тесты Cypress (cy.request).
- Нагрузочные и перформанс тесты (отдельный инструмент).
- Запуск в CI: smoke → интеграция → full-regression.
Совет: отделяйте unit и интеграционные тесты — unit быстрее и даёт локальную гарантию корректности логики, интеграционные обеспечивают совместную работу компонентов.
Когда подход с Cypress может не подойти (контрпримеры)
- Нагрузочное тестирование и стресс-тесты: Cypress не предназначен для высоконагруженных тестов — используйте k6, Gatling или JMeter.
- Сложная эмуляция внешних сервисов с нестабильной задержкой: для этих задач лучше применять специализированные моки/песочницы.
- Тестирование чисто серверных процессов без HTTP-интерфейсов: здесь подходят unit-тесты и фреймворки уровня Jest/Mocha.
Альтернативные подходы
- Supertest + Jest/Mocha: популярная связка для интеграционных тестов Node.js приложений. Хороша для тестов на уровне HTTP без запуска браузера.
- Postman / Newman: удобен для ручного тестирования и автоматизации коллекций в CI.
- Pact/Contract testing: если нужны контракты между командами, стоит подумать о контрактных тестах.
Сравнение:
- Cypress: отлично для E2E и простых API-интеграций в экосистеме JS.
- Supertest: легковесно и прямолинейно для интеграций сервера.
- Postman: удобен для интерфейсного тестирования и обмена коллекциями с командой.
CI/CD: запуск Cypress в headless режиме
Пример npm-скрипта для CI (headless):
"cypress:run": "npx cypress run"В CI определите шаги:
- Поднять ephemeral окружение сервера (docker-compose или развертывание).
- Запустить миграции/фикстуры.
- Выполнить npx cypress run.
- Собирать артефакты: видео, логи, скриншоты при падениях.
Безопасность и конфиденциальность
- Никогда не храните реальные пароли или персональные данные в фикстурах в открытом виде.
- Для чувствительных данных используйте секреты CI и локальные переменные окружения.
- В продакшне — всегда HTTPS и проверка сертификатов.
Риск-матрица и смягчающие меры
| Риск | Вероятность | Влияние | Смягчение |
|---|---|---|---|
| Флейки-тесты | Средняя | Среднее | Повторные запуски, стабилизация фикстур |
| Утечка тестовых данных | Низкая | Высокое | Хранение секретов в vault, очистка данных |
| Неправильные ожидания в тестах | Средняя | Среднее | Ревью тестов и pair-testing |
Примеры расширенных проверок и приёмо-сдаточные тесты
- Проверить, что при повторной регистрации с тем же username API возвращает корректный код (например, 409) — если так определено в API.
- Проверить, что список пользователей не содержит пароли в ответе.
- Тест на время отклика: базовое ожидание, например, ответ приходит менее 500 мс (без выдуманных слепков, ориентируйтесь на реальные SLA).
Советы по устранению ошибок и отладке
- Включите подробное логирование на сервере и собирайте логи при падениях тестов.
- Используйте cy.log и console.log в тестах и сервере для трассировки.
- В CI собирайте скриншоты и видео: Cypress умеет это делать автоматически при падении.
Модель принятия решений при выборе инструмента (Mermaid)
flowchart TD
A[Нужно ли тестировать HTTP API?] --> B{Нагрузочное тестирование?}
B -- Да --> C[k6 / Gatling]
B -- Нет --> D{Нужно ли интегрировать с UI?}
D -- Да --> E[Cypress]
D -- Нет --> F{Только Node.js среда?}
F -- Да --> G[Supertest + Jest]
F -- Нет --> H[Postman/Newman]
## Совместимость и миграция
- Cypress поддерживает Node.js текущих LTS-версий. При обновлении Node или Cypress проверяйте breaking changes в changelog.
- Для миграции от Supertest к Cypress: адаптируйте тесты с использованием cy.request и учтите особенности асинхронности.
## Короткий playbook: шаги от нуля до CI
1. Создать API и минимальные эндпоинты.
2. Настроить cypress.config.js с baseUrl.
3. Написать фикстуры в cypress/fixtures.
4. Создать e2e тесты в cypress/e2e.
5. Локально запустить node server.js и npx cypress open для отладки.
6. Добавить npx cypress run в CI шаг и собрать артефакты.
## Примеры тестов для граничных случаев
- Пустое тело запроса при регистрации — ожидаем 400 с сообщением о валидации.
- Длинные строки в username и password — проверка лимитов.
- Одновременные запросы регистрации — возможные race conditions.
## Итог и рекомендации
Cypress — мощный инструмент для интеграционных и E2E тестов, который удобно использовать в JavaScript-проектах. Для API тестирования он предоставляет удобный cy.request и интеграцию с браузерной автоматикой. Однако для нагрузочного тестирования и сложной симуляции внешних сервисов лучше выбирать специализированные решения.
Важно: комбинируйте unit-, интеграционные и контрактные тесты, чтобы достичь надёжности и покрыть разные уровни ответственности системы.
Краткие рекомендации:
- Покрывайте основные сценарии (позитив/негатив).
- Используйте фикстуры и моки для детерминированности.
- Интегрируйте тесты в CI и собирайте артефакты при падении.
---
Конец руководства.Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone