Integrationstests für C++ mit Docker: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Integrationstests für C++ mit Docker: Fortgeschrittenes Niveau

\n\n

Integrationstests 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\n

1. Architektur der Testumgebung mit Docker

\n\n

Der 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\n

Betrachten wir ein Beispiel für einen C++-Mikrodienst, der PostgreSQL und Redis verwendet. Die Datei docker-compose.test.yml:

\n\n
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\n

Wichtige 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
\n\n

2. Schreiben von Integrationstests in C++ unter Berücksichtigung von Docker

\n\n

Ihre 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\n

Beispiel 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                

Blogs

Buchempfehlungen