← Назад к вопросам

Приведи пример интеграционного тестирования WEB

1.3 Junior🔥 191 комментариев
#Теория тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример интеграционного тестирования веб-приложения

Интеграционное тестирование (Integration Testing) — это уровень тестирования, на котором отдельные программные модули объединяются и тестируются как группа. В контексте Web-приложений это означает проверку взаимодействия между различными компонентами системы: клиентской частью (frontend), серверной частью (backend), базами данных, внешними API и другими сервисами.

Конкретный сценарий: процесс оформления заказа в интернет-магазине

Рассмотрим типичный пользовательский сценарий: "Пользователь добавляет товар в корзину и завершает оформление заказа".

Цель теста: Убедиться, что все компоненты системы (UI, бэкенд-сервисы, база данных, платежный шлюз, сервис уведомлений) корректно взаимодействуют друг с другом для выполнения сквозной бизнес-операции.

Тестовые компоненты:

  • Frontend (React-приложение)
  • Backend API (Node.js + Express)
  • База данных (PostgreSQL)
  • Внешний платежный сервис (имитация Stripe)
  • Сервис отправки email (имитация SendGrid)

Шаги выполнения теста (Сценарий)

  1. Инициализация: Очистка тестовых данных, запуск тестовой среды с подключенными всеми сервисами (например, с использованием Docker Compose).
  2. Действие на фронтенде: Симуляция входа пользователя в систему (отправка запроса на аутентификацию).
  3. Взаимодействие с каталогом: Добавление товара в корзину через UI. Это вызывает API-запрос к бэкенду.
  4. Обработка бэкендом: Бэкенд принимает запрос, проверяет авторизацию, обновляет запись корзины в БД и возвращает обновленные данные на фронтенд.
  5. Переход к оформлению: Симуляция перехода на страницу оформления заказа и ввода адреса доставки.
  6. Инициация платежа: Симуляция нажатия кнопки "Оплатить". Фронтенд отправляет запрос на создание платежного намерения (Payment Intent) в бэкенд.
  7. Интеграция с платежным шлюзом: Бэкенд вызывает внешний API платежного сервиса, получает ключ клиента (client secret) и возвращает его фронтенду.
  8. Симуляция успешного платежа: В тестовой среде имитируется успешный ответ от платежного шлюза (без реального списания денег).
  9. Создание заказа: Бэкенд, получив подтверждение об успешном платеже:
    *   Создает запись заказа в БД со статусом `PAID`.
    *   Уменьшает количество товара на складе (обновляет БД).
    *   Формирует и ставит в очередь задание на отправку письма-подтверждения.
  1. Проверка уведомления: Тест проверяет, что задание для email-сервиса было создано (или что мокированный сервис получил корректный вызов).
  2. Верификация состояния системы: Финальная проверка, что данные во всех системах согласованы:
    *   В БД заказ имеет правильный статус.
    *   Баланс корзины пользователя обнулен.
    *   Количество товара на складе уменьшилось ровно на заказанное.

Пример кода (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** для запуска всей среды (БД, кеш, воркеры) в изоляции.
    *   **Наблюдаемость:** Логирование всех шагов и межсервисных вызовов для упрощения отладки.

Вывод: Интеграционное тестирование веб-приложения фокусируется на потоках данных и контрольных точках между компонентами. Успешный тест демонстрирует, что система работает как единое целое, а не просто что каждый модуль корректен сам по себе (это проверяет модульное тестирование). Это критически важный этап для выявления проблем, которые неизбежно возникают при взаимодействии независимо разработанных частей приложения.