Why "just unit tests" is no longer enough?
\n\nYou wrote perfect C++ code. Compilation passed, unit tests are green, code review approved. You roll out the release — and an hour later users complain: "the button doesn't work", "the database is not responding", "the GUI freezes". Sound familiar?
\n\nThe problem is that unit tests check a function, but they don't check a scenario. They are isolated. But in the real world, your C++ code interacts with the network, file system, GPU, external APIs, and other threads. This is where E2E testing of C++ applications (End-to-End testing) comes into play.
\n\nIn this article, we will break down how to turn the chaos of integration errors into a streamlined system of automated checks. You will learn which tools actually work, how to write tests that won't fall apart on the first run, and how to embed E2E into a CI/CD pipeline. Let's go!
\n\nWhat is E2E testing in the context of C++?
\n\nE2E testing is the verification of a complete user scenario "from start to finish". Unlike unit tests, which check a single function, an E2E test runs your application (or its critically important part) in an environment as close to production as possible.
\n\nFor C++, this could mean:
\n- \n
- Desktop application: launching a window, clicking the "Submit" button, verifying that the data went to the database. \n
- Server application: sending an HTTP request to your REST API, checking the response and the database state. \n
- Embedded/Software: applying a signal to the input, checking the output signal after a certain time. \n
The key difference is the real environment. No mock objects for the database or network. Only live hardware (or Docker).
\n\nToolkit: What actually works for C++ in 2024?
\n\nLet's get straight to the point. Here is the stack we use in production:
\n\n- \n
- Catch2 or Google Test — for writing the test structure (Arrange-Act-Assert). \n
- Docker — for spinning up a clean environment (DB, queues, dependencies). \n
- Pytest + subprocess — for orchestration (yes, Python, but it's ideal for gluing C++ binaries together). \n
- Selenium/Appium — if you have a GUI on Qt or WebView. \n
- CMake + CTest — for running tests and collecting results. \n
Don't try to write E2E tests only in C++. It's painful. Use Python as glue — it's faster for integration scenarios.
\n\nPractice: Writing an E2E test for a REST API in C++
\n\nLet's say we have a C++ server using cpp-httplib (or crow, or drogon). It accepts POST requests at /api/user and saves the user to PostgreSQL.
Let's write an E2E test that:
\n- \n
- Spins up a Docker container with PostgreSQL. \n
- Compiles and runs our server. \n
- Sends an HTTP request via curl (or a C++ client). \n
- Checks that the user appeared in the database. \n
Step 1: Docker-compose for the test environment
\n\nversion: '3.8'\nservices:\n db:\n image: postgres:15\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: testuser\n POSTGRES_PASSWORD: testpass\n ports:\n - "5432:5432"\n app:\n build: .\n depends_on:\n - db\n ports:\n - "8080:8080"\n environment:\n DB_HOST: db\n\n\nStep 2: Test in C++ using Catch2
\n\n// test_e2e_api.cpp\n#include <catch2/catch_test_macros.hpp>\n#include <httplib.h>\n#include <nlohmann/json.hpp>\n#include <cstdlib>\n\nTEST_CASE("E2E: Create user via API and verify in DB") {\n // Arrange\n httplib::Client cli("localhost", 8080);\n nlohmann::json user = {\n {"name", "John Doe"}