Table of Contents
Motivation
So, auf geht’s! Test Driven Development für C++ Projekte.
Google Test (oft auch als gtest abgekürzt) ist ein Test Framework, das von Google entwickelt wurde. 2008 wurde es als Open Source veröffentlicht, seit 2015 findest du es auf github.
Voraussetzungen
Um Google Test in deinen Projekten verwenden zu können, musst du CMake installiert haben. Zudem empfiehlt es sich, dein Projekt mit git zu versionieren, weil du dann Google Test als git Submodul installieren kannst.
Installation
cd my_project
git submodule add https://github.com/google/googletest.git external/googletest
git submodule update --init --recursive
CMake
cmake_minimum_required(VERSION 3.14)
project(my_project)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(external/googletest)
include(GoogleTest)
enable_testing()
add_executable(google_test_examples tests/00_google_test.cpp)
target_link_libraries(google_test_examples gtest_main)
gtest_discover_tests(google_test_examples)
Code
#include <gtest/gtest.h>
Standard Vergleiche
Standardmäßig vergleicht man gerne auf Gleichheit beziehungsweise Ungleichheit.
TEST(GoogleTestExamples, EXPECT_EQ) {
const int a = 10;
const int b = 10;
EXPECT_EQ(a, b);
}
TEST(GoogleTestExamples, EXPECT_NE) {
const int a = 10;
const int b = 11;
EXPECT_NE(a, b);
}
Auch bool’sche Ausdrücke lassen sich vergleichen, auf true oder false. Das wäre aber auch schon mit dem eingebauten Assert direkt in C++ möglich. Deswegen schauen wir uns spannendere Testfälle an:
Float und double vergleichen
TEST(GoogleTestExamples, EXPECT_FLOAT_EQ) {
const float a = 10.0;
const float b = 10.000001;
EXPECT_FLOAT_EQ(a, b);
}
TEST(GoogleTestExamples, EXPECT_DOUBLE_EQ) {
const float a = 10.0;
const float b = 10.0000001;
EXPECT_DOUBLE_EQ(a, b);
}
Exceptions testen
Schön ist es, dass Google Test auch das Testen von Exceptions unterstützt:
TEST(GoogleTestExamples, ArrayException) {
constexpr std::array<int, 3> my_array = {1,2,3};
EXPECT_THROW((void)my_array.at(10), std::out_of_range);
}
Tests ausführen
Um die Tests auszuführen, wechseln wir in das Build-Verzeichnis und starten die Tests über ctest:
cd cmake-build-debug
ctest
Test Fixtures
Wenn man schon etwas Erfahrung mit dem Erstellen von Tests hat, genießt man Features wie Test Fixtures.
Ein Test Fixture ist eine Methode, wie man für eine Vielzahl von Tests die Startbedingungen festlegen kann. Variablen initialisieren und Objekte instantiieren beispielsweise.
In klassischen Testframeworks wie JUnit oder auch Python Unittest muss man dafür die Setup-Methode der Testklasse verwenden. In modernen Testframeworks wie pytest, sind fixtures freistehende Funktionen.
In Google Test besteht ein Fixture aus einer Klasse die von ::testing::Test erbt und die SetUp()-Methode überschreibt.
class TestFixture : public ::testing::Test {
protected:
void SetUp() override {
speed = 100;
}
int speed{};
};
Dann können wir mit dem Test-Makro TEST_F das Fixture verwenden:
TEST_F(TestFixture, IncreasesSpeed) {
speed += 50;
EXPECT_EQ(speed, 150);
}
TEST_F(TestFixture, DecreasesSpeed) {
speed -= 30;
EXPECT_EQ(speed, 70);
}
Parametrisierte Tests
Parametrisierung Tests sind ein sehr wertvolles Werkzeug, gerade wenn man TDD benutzt, um seine Programme zu schreiben.
Bei the Rule of three führt man normalerweise eine Optimierung durch, sobald man dreimal das Gleiche getan hat.
Oft ist das der Aufruf einer neuen Funktion mit einem dritten Parameter.
Deshalb könnte dann hier ein parametrisierter Test drei Testfälle ersetzen.
class AbsTest : public ::testing::TestWithParam<std::pair<int, int>> {
// no setup needed
};
TEST_P(AbsTest, ComputesAbsoluteValue) {
int input = GetParam().first;
int expected = GetParam().second;
EXPECT_EQ(std::abs(input), expected);
}
INSTANTIATE_TEST_SUITE_P(
AbsValues,
AbsTest,
::testing::Values(
std::make_pair(-3, 3),
std::make_pair(-1, 1),
std::make_pair(0, 0),
std::make_pair(2, 2)
)
);
Test Reports erstellen
In größeren Projekten wird gerne für die Weiterverarbeitung ein Report in HTML oder XML erwartet,
der sich zum Beispiel für den Import in ein Quality Gate Tool wie Sonar Cube eignet.
In Google Test erreicht man dies, in dem man ctest so ausführt:
ctest --output-junit test-report.xml
Übersicht Test Makros
| Assertion | Bedeutung |
| EXPECT_EQ(a, b) | a == b |
| EXPECT_NE(a, b) | a != b |
| EXPECT_LT(a, b) | a < b |
| EXPECT_LE(a, b) | a <= b |
| EXPECT_GT(a, b) | a > b |
| EXPECT_GE(a, b) | a >= b |
| EXPECT_TRUE(expr) | Ausdruck ist **true** |
| EXPECT_FALSE(expr) | Ausdruck ist **false** |
| EXPECT_STREQ(a, b) | zwei const char* sind gleich |
| EXPECT_STRNE(a, b) | zwei const char* sind ungleich |
| EXPECT_FLOAT_EQ(a, b) | zwei float sind „nahe genug“ |
| EXPECT_DOUBLE_EQ(a, b) | zwei double sind „nahe genug“ |
Fazit
Google Test ist ein angenehmes Test-Framework mit einer entspannten Lernkurve.
Die Integration in moderne IDEs wie Jetbrains CLion ist ein weiterer Pluspunkt.
Den gesamten Code findest du hier: https://github.com/jboegeholz/modern_cpp/blob/master/tests/00_google_test.cpp
Weiterführende Links
https://creatronix.de/software-testing-concepts/
https://creatronix.de/wie-tdd-die-welt-rettet-und-deine-nerven-schont/
https://creatronix.de/wie-baue-ich-eine-entwicklungsbegleitende-software-qualitatssicherung-auf/






