Integrationstests für C++ mit Docker: Fortgeschrittenes Niveau
\n\nIntegrationstests sind ein kritisch wichtiger Schritt in der C++-Entwicklung, insbesondere in modernen Mikrodienstarchitekturen. Traditionelle Ansätze, bei denen Tests in der Entwicklungsumgebung ausgeführt werden, führen oft zu Fehlern aufgrund von Unterschieden in der Umgebung, Bibliotheksversionen und Konfigurationen. Docker bietet eine elegante Lösung: vollständige Isolierung, Reproduzierbarkeit und Automatisierung. In diesem Artikel betrachten wir fortgeschrittene Techniken für Integrationstests von C++-Anwendungen mit Docker, einschließlich Abhängigkeitsverwaltung, parallelem Teststart und Integration in CI/CD.
\n\n1. Architektur der Testumgebung mit Docker
\n\nDer erste Schritt zu zuverlässigen Integrationstests ist die richtige Architektur der Docker-Umgebung. Anstelle eines einzelnen monolithischen Containers erstellen wir eine Komposition von Diensten, von denen jeder für seine eigene Aufgabe verantwortlich ist: der zu testende Dienst selbst, die Datenbank, der Cache, Nachrichtenwarteschlangen usw.
\n\nBetrachten wir ein Beispiel für einen C++-Mikrodienst, der PostgreSQL und Redis verwendet. Die Datei docker-compose.test.yml:
version: '3.8'\n\nservices:\n postgres_test:\n image: postgres:15-alpine\n environment:\n POSTGRES_USER: test_user\n POSTGRES_PASSWORD: test_pass\n POSTGRES_DB: test_db\n healthcheck:\n test: ["CMD-SHELL", "pg_isready -U test_user -d test_db"]\n interval: 2s\n timeout: 5s\n retries: 10\n\n redis_test:\n image: redis:7-alpine\n healthcheck:\n test: ["CMD", "redis-cli", "ping"]\n interval: 2s\n timeout: 5s\n retries: 10\n\n cpp_service_test:\n build:\n context: .\n dockerfile: Dockerfile.test\n depends_on:\n postgres_test:\n condition: service_healthy\n redis_test:\n condition: service_healthy\n environment:\n - DB_HOST=postgres_test\n - DB_PORT=5432\n - REDIS_HOST=redis_test\n - REDIS_PORT=6379\n - TEST_MODE=1\n volumes:\n - ./test_results:/app/test_results\n command: ["./run_integration_tests"]\n\nWichtige Punkte:
\n- \n
- Healthchecks stellen sicher, dass die Tests erst starten, wenn die Abhängigkeiten bereit sind. \n
- Ein separates Netzwerk (wird automatisch erstellt) isoliert die Testumgebung von der Produktion. \n
- Ein Volume für Ergebnisse ermöglicht das Abrufen von Testberichten nach Abschluss. \n
2. Schreiben von Integrationstests in C++ unter Berücksichtigung von Docker
\n\nIhre Tests sollten bereit sein, in einer containerisierten Umgebung zu arbeiten. Das bedeutet, dass die Konfiguration der Verbindung zu externen Diensten über Umgebungsvariablen erfolgen sollte, nicht hartcodiert sein darf.
\n\nBeispiel eines Tests mit Google Test und libpqxx für PostgreSQL:
\n\n#include <gtest/gtest.h>\n#include <pqxx/pqxx>\n#include <cstdlib>\n\nclass DatabaseIntegrationTest : public ::testing::Test {\nprotected:\n std::unique_ptr<pqxx::connection> conn;\n\n void SetUp() override {\n const char* db_host = std::getenv("DB_HOST");\n const char* db_port = std::getenv("DB_PORT");\n const char* db_user = std::getenv("POSTGRES_USER");\n const char* db_pass = std::getenv("POSTGRES_PASSWORD");\n const char* db_name = std::getenv("POSTGRES_DB");\n\n ASSERT_NE(db_host, nullptr) << "DB_HOST not set";\n ASSERT_NE(db_port, nullptr) << "DB_PORT not set";\n\n std::string conn_str = "host=" + std::string(db_host) +\n " port=" + std::string(db_port) +\n " user=" + std::string(db_user ? db_user : "test_user") +\n " password=" + std::string(db_pass ? db_pass : "test_pass") +\n " dbname=" + std::string(db_name ? db_name : "test_db");\n\n try {\n conn = std::make_unique<pqxx::connect