Testen in C++: Überblick über Frameworks und Tools (Google Test, Catch2, doctest)

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

Testen in C++: Frameworks und Tools



Qualitätssicherung durch Tests ist ein wesentlicher Bestandteil der C++-Entwicklung. Im Gegensatz zu dynamischen Sprachen erfordert C++ besondere Aufmerksamkeit bei der Speicherverwaltung, der Lebensdauer von Objekten und der Leistung. In diesem Artikel betrachten wir die drei beliebtesten Frameworks für Modultests: Google Test, Catch2 und doctest, und gehen auch auf zusätzliche Werkzeuge ein.



Warum ist Testen in C++ wichtig?

C++ ist eine Sprache mit manueller Speicherverwaltung und leistungsstarker Template-Magie. Ohne Tests können leicht folgende Fehler auftreten:

  • Speicherlecks und doppelte Freigabe
  • Undefiniertes Verhalten (UB) bei der Arbeit mit Zeigern
  • Fehler bei der Überladung von Operatoren und Kopierkonstruktoren
  • Regressionen bei der Refaktorisierung von Legacy-Code

Test-Frameworks automatisieren die Überprüfung und helfen, Probleme schnell zu finden.



Google Test (gtest)

Das am weitesten verbreitete Framework von Google. Es unterstützt alle grundlegenden Funktionen: Makros ASSERT_* und EXPECT_*, parametrisierte Tests, Test-Fixuren (test fixtures), Death-Tests.



Installation (über CMake FetchContent)

include(FetchContent)FetchContent_Declare(  googletest  GIT_REPOSITORY https://github.com/google/googletest.git  GIT_TAG release-1.14.0)FetchContent_MakeAvailable(googletest)


Beispiel eines einfachen Tests

#include <gtest/gtest.h>

int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n - 1);}

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

TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(factorial(5), 120); EXPECT_EQ(factorial(3), 6);}

int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();}


Fixuren und parametrisierte Tests

class MathFixture : public ::testing::Test {protected:    void SetUp() override { /* Initialisierung */ }    void TearDown() override { /* Bereinigung */ }};

// Parametrisierter Testclass SumTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};TEST_P(SumTest, CheckSum) { auto [a, b, expected] = GetParam(); EXPECT_EQ(a + b, expected);}INSTANTIATE_TEST_SUITE_P(SumParams, SumTest, ::testing::Values( std::make_tuple(1, 1, 2), std::make_tuple(0, 0, 0) ));


Vorteile: riesige Community, Integration in CI/CD, leistungsstarke Makros, Unterstützung von Death-Tests.
Nachteile: relativ langsame Kompilierung, große Größe der ausführbaren Datei.



Catch2

Ein modernes Framework mit Fokus auf Lesbarkeit der Tests. Es verwendet den BDD-Stil (Behaviour-Driven Development) und unterstützt Sektionen (sections).



Installation (header-only)

Catch2 wird als einzelne Header-Datei verteilt. Es reicht aus, catch_amalgamated.hpp herunterzuladen und einzubinden.



Beispiel mit Sektionen

#define CATCH_CONFIG_MAIN#include <catch2/catch.hpp>

int divide(int a, int b) { if (b == 0) throw std::invalid_argument("division by zero"); return a / b;}

TEST_CASE("Division tests", "[math]") { SECTION("Normal division") { REQUIRE(divide(10, 2) == 5); } SECTION("Division by zero") { REQUIRE_THROWS_AS(divide(5, 0), std::invalid_argument); }}


BDD-Stil (Given-When-Then)

SCENARIO("Vector push_back operation", "[container]") {    GIVEN("An empty vector") {        std::vector<int> v;        WHEN("We push one element") {            v.push_back(42);            THEN("The size becomes 1") {                REQUIRE(v.size() == 1);            }            AND_THEN("The element is correct") {                REQUIRE(v[0] == 42);                    

Empfehlungen