E2E тестирование C++ приложений: от теории до боевого CI/CD

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему «просто юнит-тестов» уже недостаточно?

Вы написали идеальный код на C++. Компиляция прошла, юнит-тесты зелёные, code review одобрили. Выкатываете релиз — и через час пользователи жалуются: «кнопка не нажимается», «база данных не отвечает», «GUI зависает». Знакомо?

Проблема в том, что юнит-тесты проверяют функцию, но не проверяют сценарий. Они изолированы. А в реальном мире ваш C++ код взаимодействует с сетью, файловой системой, GPU, внешними API и другими потоками. Именно здесь в игру вступает E2E тестирование C++ приложений (End-to-End или сквозное тестирование).

В этой статье мы разберём, как превратить хаос интеграционных ошибок в стройную систему автоматических проверок. Вы узнаете, какие инструменты реально работают, как писать тесты, которые не развалятся при первом запуске, и как встроить E2E в CI/CD пайплайн. Поехали!

Что такое E2E тестирование в контексте C++?

E2E тестирование — это проверка полного пользовательского сценария «от начала до конца». В отличие от модульных тестов, которые проверяют отдельную функцию, E2E тест запускает ваше приложение (или его критически важную часть) в среде, максимально приближенной к production.

Для C++ это может означать:

  • Desktop приложение: запуск окна, клик по кнопке «Отправить», проверка, что данные ушли в БД.
  • Серверное приложение: отправка HTTP-запроса к вашему REST API, проверка ответа и состояния базы.
  • Embedded/ПО: подача сигнала на вход, проверка выходного сигнала через определённое время.

Ключевое отличие — реальная среда. Никаких mock-объектов для базы данных или сети. Только живое железо (или Docker).

Инструментарий: что реально работает для C++ в 2024?

Давайте сразу к делу. Вот стэк, который мы используем в бою:

  • Catch2 или Google Test — для написания структуры тестов (Arrange-Act-Assert).
  • Docker — для поднятия чистого окружения (БД, очереди, зависимости).
  • Pytest + subprocess — для оркестрации (да, Python, но он идеален для склеивания C++ бинарников).
  • Selenium/Appium — если у вас GUI на Qt или WebView.
  • CMake + CTest — для запуска тестов и сбора результатов.

Не пытайтесь писать E2E тесты только на C++. Это больно. Используйте Python как клей — он быстрее для интеграционных сценариев.

Практика: пишем E2E тест для REST API на C++

Допустим, у нас есть C++ сервер на cpp-httplib (или crow, или drogon). Он принимает POST запросы по адресу /api/user и сохраняет пользователя в PostgreSQL.

Напишем E2E тест, который:

  1. Поднимает Docker контейнер с PostgreSQL.
  2. Компилирует и запускает наш сервер.
  3. Отправляет HTTP запрос через curl (или C++ клиент).
  4. Проверяет, что пользователь появился в БД.

Шаг 1: Docker-compose для тестового окружения

version: '3.8'
services:
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: testdb
      POSTGRES_USER: testuser
      POSTGRES_PASSWORD: testpass
    ports:
      - "5432:5432"
  app:
    build: .
    depends_on:
      - db
    ports:
      - "8080:8080"
    environment:
      DB_HOST: db

Шаг 2: Тест на C++ с использованием Catch2

// test_e2e_api.cpp
#include <catch2/catch_test_macros.hpp>
#include <httplib.h>
#include <nlohmann/json.hpp>
#include <cstdlib>

TEST_CASE("E2E: Create user via API and verify in DB") {
    // Arrange
    httplib::Client cli("localhost", 8080);
    nlohmann::json user = {
        {"name", "John Doe"},
        {"email", "john@example.com"}
    };

    // Act
    auto res = cli.Post("/api/user", user.dump(), "application/json");

    // Assert
    REQUIRE(res->status == 201);
    REQUIRE(res->body == "User created");

    // Проверка через прямой запрос к БД (через системную команду)
    // В реальном проекте лучше использовать libpqxx
    std::string cmd = R"(psql -h localhost -U testuser -d testdb -c "SELECT * FROM users WHERE email='john@example.com';")";
    int result = std::system(cmd.c_str());
    REQUIRE(result == 0);
}

Этот тест запускается как обычный Catch2 бинарник. Но он требует, чтобы Docker был запущен и сервер работал. Как это автоматизировать?

Шаг 3: Оркестрация через Python (pytest + subprocess)

Создаём файл conftest.py:

import subprocess
import time
import pytest

@pytest.fixture(scope="session")
def docker_env():
    # Поднимаем окружение
    subprocess.run(["docker-compose", "up", "-d", "--build"], check=True)
    time.sleep(5)  # Ждём инициализации БД
    yield
    # Чистим после всех тестов
    subprocess.run(["docker-compose", "down", "-v"], check=True)

def test_e2e_cpp_app(docker_env):
    # Запускаем наш C++ тестовый бинарник
    result = subprocess.run(
        ["./build/test_e2e_api"],
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"E2E test failed:\n{result.stdout}\n{result.stderr}"

Теперь одной командой pytest мы поднимаем окружение, запускаем C++ тесты и чистим за собой. Это и есть настоящая автоматизация E2E тестирования C++ приложений.

E2E для Desktop приложений (Qt, wxWidgets)

Если ваше C++ приложение имеет GUI, подход меняется. Вам нужен инструмент, который умеет кликать по кнопкам и читать текст на экране.

Вариант 1: Squish (коммерческий, но мощный)

Squish от froglogic умеет записывать скрипты для Qt, QML и Web. Вы пишете тест на Python или JavaScript, а Squish эмулирует действия пользователя.

Вариант 2: OpenCV + pyautogui (бесплатно, но хрупко)

Для простых случаев можно находить кнопки по скриншотам:

import pyautogui
import subprocess
import time

# Запускаем приложение
proc =                

Блоги

Рекомендаций по книгам