Приведи пример интеграционного тестирования WEB
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример интеграционного тестирования веб-приложения
Интеграционное тестирование (Integration Testing) — это уровень тестирования, на котором отдельные программные модули объединяются и тестируются как группа. В контексте Web-приложений это означает проверку взаимодействия между различными компонентами системы: клиентской частью (frontend), серверной частью (backend), базами данных, внешними API и другими сервисами.
Конкретный сценарий: процесс оформления заказа в интернет-магазине
Рассмотрим типичный пользовательский сценарий: "Пользователь добавляет товар в корзину и завершает оформление заказа".
Цель теста: Убедиться, что все компоненты системы (UI, бэкенд-сервисы, база данных, платежный шлюз, сервис уведомлений) корректно взаимодействуют друг с другом для выполнения сквозной бизнес-операции.
Тестовые компоненты:
- Frontend (React-приложение)
- Backend API (Node.js + Express)
- База данных (PostgreSQL)
- Внешний платежный сервис (имитация Stripe)
- Сервис отправки email (имитация SendGrid)
Шаги выполнения теста (Сценарий)
- Инициализация: Очистка тестовых данных, запуск тестовой среды с подключенными всеми сервисами (например, с использованием Docker Compose).
- Действие на фронтенде: Симуляция входа пользователя в систему (отправка запроса на аутентификацию).
- Взаимодействие с каталогом: Добавление товара в корзину через UI. Это вызывает API-запрос к бэкенду.
- Обработка бэкендом: Бэкенд принимает запрос, проверяет авторизацию, обновляет запись корзины в БД и возвращает обновленные данные на фронтенд.
- Переход к оформлению: Симуляция перехода на страницу оформления заказа и ввода адреса доставки.
- Инициация платежа: Симуляция нажатия кнопки "Оплатить". Фронтенд отправляет запрос на создание платежного намерения (Payment Intent) в бэкенд.
- Интеграция с платежным шлюзом: Бэкенд вызывает внешний API платежного сервиса, получает ключ клиента (client secret) и возвращает его фронтенду.
- Симуляция успешного платежа: В тестовой среде имитируется успешный ответ от платежного шлюза (без реального списания денег).
- Создание заказа: Бэкенд, получив подтверждение об успешном платеже:
* Создает запись заказа в БД со статусом `PAID`.
* Уменьшает количество товара на складе (обновляет БД).
* Формирует и ставит в очередь задание на отправку письма-подтверждения.
- Проверка уведомления: Тест проверяет, что задание для email-сервиса было создано (или что мокированный сервис получил корректный вызов).
- Верификация состояния системы: Финальная проверка, что данные во всех системах согласованы:
* В БД заказ имеет правильный статус.
* Баланс корзины пользователя обнулен.
* Количество товара на складе уменьшилось ровно на заказанное.
Пример кода (Node.js + Jest + Supertest)
const request = require('supertest');
const { app, server } = require('../../app'); // Экспресс-приложение
const db = require('../../models');
const stripe = require('stripe')(process.env.STRIPE_TEST_KEY);
const emailService = require('../../services/emailService');
// Мокируем внешние сервисы
jest.mock('../../services/emailService');
jest.mock('stripe');
describe('Интеграционный тест: Оформление заказа', () => {
let authToken;
let productId;
let cartId;
let testUserId;
beforeAll(async () => {
// 1. Подготовка: создаем тестовые данные в БД
await db.sequelize.sync({ force: true });
const user = await db.User.create({ email: 'test@test.com', password: 'hash' });
testUserId = user.id;
const product = await db.Product.create({ name: 'Тестовый товар', price: 1000, stock: 10 });
productId = product.id;
// Логинимся для получения токена
const loginRes = await request(app)
.post('/api/auth/login')
.send({ email: 'test@test.com', password: 'password123' });
authToken = loginRes.body.token;
});
test('Полный цикл от корзины до подтверждения заказа', async () => {
// 2. Добавляем товар в корзину
const addToCartRes = await request(app)
.post('/api/cart/items')
.set('Authorization', `Bearer ${authToken}`)
.send({ productId, quantity: 2 });
expect(addToCartRes.statusCode).toBe(201);
cartId = addToCartRes.body.cartId;
// 3. Создаем заказ и инициируем платеж
const createOrderRes = await request(app)
.post('/api/orders')
.set('Authorization', `Bearer ${authToken}`)
.send({ cartId, address: 'Тестовый адрес' });
expect(createOrderRes.statusCode).toBe(201);
const { orderId, clientSecret } = createOrderRes.body;
// 4. Имитируем успешный ответ от Stripe
stripe.paymentIntents.confirm.mockResolvedValue({ status: 'succeeded' });
// 5. Подтверждаем платеж на бэкенде
const confirmPaymentRes = await request(app)
.post(`/api/orders/${orderId}/confirm-payment`)
.set('Authorization', `Bearer ${authToken}`)
.send({ paymentIntentId: 'test_pi_123', clientSecret });
expect(confirmPaymentRes.statusCode).toBe(200);
// 6. Проверяем состояние в БД
const finalOrder = await db.Order.findByPk(orderId);
expect(finalOrder.status).toBe('PAID');
const updatedProduct = await db.Product.findByPk(productId);
expect(updatedProduct.stock).toBe(8); // Было 10, купили 2
const userCart = await db.Cart.findOne({ where: { userId: testUserId, status: 'ACTIVE' } });
expect(userCart).toBeNull(); // Корзина должна быть очищена
// 7. Проверяем, что сервис уведомлений был вызван с правильными данными
expect(emailService.sendOrderConfirmation).toHaveBeenCalledTimes(1);
expect(emailService.sendOrderConfirmation).toHaveBeenCalledWith(
'test@test.com',
expect.objectContaining({ id: orderId })
);
});
afterAll(async () => {
await db.sequelize.close();
server.close();
});
});
Ключевые аспекты и инструменты
- Изоляция: Тесты должны работать с тестовой БД и моками/стабами для внешних сервисов, чтобы не влиять на продакшен и быть детерминированными.
- Данные: Важно управлять состоянием данных до и после теста (setup/teardown).
- Инструменты:
* **API-тестирование:** Supertest, Postman/Newman, REST Assured.
* **Моки/Стабы:** Jest, Sinon.JS, WireMock для имитации внешних API.
* **Управление зависимостями:** **Docker Compose** для запуска всей среды (БД, кеш, воркеры) в изоляции.
* **Наблюдаемость:** Логирование всех шагов и межсервисных вызовов для упрощения отладки.
Вывод: Интеграционное тестирование веб-приложения фокусируется на потоках данных и контрольных точках между компонентами. Успешный тест демонстрирует, что система работает как единое целое, а не просто что каждый модуль корректен сам по себе (это проверяет модульное тестирование). Это критически важный этап для выявления проблем, которые неизбежно возникают при взаимодействии независимо разработанных частей приложения.