Testen in C++: Unit-, Integrations- und E2E-Tests. Vollständiger Leitfaden

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

Einleitung: Warum Testen in C++ kein Luxus, sondern eine Notwendigkeit ist



Die Entwicklung in C++ ist stets ein Balanceakt zwischen Leistung und Zuverlässigkeit. Speicherverwaltungsfehler, undefiniertes Verhalten (UB) und komplexe Abhängigkeiten zwischen Modulen machen C++ zu einer der anspruchsvollsten Sprachen in Bezug auf Codequalität. Ohne einen systematischen Testansatz verwandelt sich ein Projekt schnell in eine "Black Box", in der die Behebung eines Fehlers zwei neue hervorbringt.



In diesem Artikel analysieren wir drei wichtige Testebenen in C++: Unit-Tests (Modultests), Integrationstests und E2E-Tests (End-to-End-Tests). Sie erfahren, welche Tools Sie verwenden sollten, wie Sie effektive Tests schreiben und wie Sie eine Testpyramide für Ihr C++-Projekt aufbauen.



1. Unit-Testing: Jeden Baustein prüfen



Unit-Tests bilden die Basis der Testpyramide. Sie prüfen isoliert eine einzelne logische Code-Einheit: eine Funktion, eine Klassenmethode oder eine kleine Struktur. In C++ sollten Unit-Tests schnell ausgeführt werden (<1 Sekunde für hunderte Tests) und nicht von externen Ressourcen (Dateisystem, Netzwerk, Datenbanken) abhängen.



Tools für C++ Unit-Testing

  • Google Test (gtest) — das beliebteste Framework von Google. Unterstützt Assertion-Makros, Fixtures und parametrisierte Tests.
  • Catch2 — eine moderne Alternative mit prägnanter Syntax und Unterstützung für den BDD-Stil.
  • Boost.Test — Teil der Boost-Bibliothek, ein ausgereiftes Tool mit umfangreichen Möglichkeiten.


Beispiel eines Unit-Tests mit Google Test

Angenommen, wir haben eine Funktion zur Berechnung der Fakultät:



// math_utils.h#pragma onceunsigned long long factorial(unsigned int n);


// math_utils.cpp#include "math_utils.h"

unsigned long long factorial(unsigned int n) { if (n == 0) return 1; unsigned long long result = 1; for (unsigned int i = 1; i <= n; ++i) { result *= i; } return result;}


Wir schreiben den Unit-Test:



// test_math_utils.cpp#include <gtest/gtest.h>#include "math_utils.h"

TEST(FactorialTest, HandlesZero) { EXPECT_EQ(factorial(0), 1);}

TEST(FactorialTest, HandlesPositiveNumbers) { EXPECT_EQ(factorial(1), 1); EXPECT_EQ(factorial(5), 120); EXPECT_EQ(factorial(10), 3628800);}

TEST(FactorialTest, HandlesLargeInput) { // 20! passt in unsigned long long EXPECT_EQ(factorial(20), 2432902008176640000ULL);}


Bewährte Praktiken für Unit-Testing in C++:

  • Ein Test — eine Prüfung. Verwenden Sie EXPECT_EQ für weiche und ASSERT_EQ für kritische Prüfungen.
  • Isolieren Sie Abhängigkeiten durch Mock-Objekte (Google Mock).
  • Testen Sie Grenzfälle: Nullwerte, Überlauf, leere Container.
  • Verwenden Sie TEST_F für wiederkehrende Initialisierungen (Fixtures).


2. Integrationstests: Wie Module zusammenarbeiten



Integrationstests prüfen die Interaktion zwischen mehreren Modulen oder Komponenten. In C++ ist dies besonders wichtig, da Fehler oft an den Schnittstellen auftreten: falsche Speicherverwaltung bei der Übergabe von Objekten, Nichtübereinstimmung von Schnittstellen oder Probleme mit der Multithreading-Fähigkeit.



Im Gegensatz zu Unit-Tests können Integrationstests mit echten Datenbanken, Dateien oder Netzwerk-Sockets arbeiten, jedoch in der Regel in einer Testumgebung (z. B. temporäre Dateien oder Docker-Container).



Beispiel eines Integrationstests

Angenommen, wir haben ein Modul Logger und ein Modul FileManager. Wir möchten überprüfen, ob die Logs korrekt in eine Datei geschrieben werden.



// file_logger.h#pragma once#include <string>

class FileLogger {public: FileLogger(const std::string& filename); vo

Blogs

Buchempfehlungen