Seite wählen

NETWAYS Blog

Code Coverage mit LCOV

Auf der Suche nach einem Tool, das „Code Coverage“-Statistiken für C-/C++-Programme generieren kann, bin ich auf LCOV gestoßen:
lcov-icinga2
LCOV generiert zu GCOV-Coverage-Daten HTML-Seiten, auf denen man sich einen Überblick darüber verschaffen kann, welche Codeteile von Unit Tests nicht abgedeckt werden.
Im Schnelldurchlauf lässt sich LCOV wie folgt verwenden:
1. Das eigene Programm muss mit dem Compiler-Flag „–coverage“ kompiliert werden, z.B.:

$ gcc -o test --coverage test.c

2. Danach entfernen wir zunächst alle alten Coverage-Daten (falls wir unser Programm vorher schonmal ausgeführt haben):

$ lcov -d . -z

3. Anschließend führen wir unser Programm aus:

$ ./test

4. Und abschließend generieren wir HTML-Seiten zum Programmlauf:

$ lcov -d . -c -o test.info
$ genhtml -o lcov-html test.info

Die HTML-Dateien werden dabei in dem mit -o angegebenen Verzeichnis erstellt.

Test-driven Development

Beim Test-driven Development handelt es sich um einen Programmieransatz des Extreme Programming, der auf Unit Tests basiert und höhere Produktivität verspricht.
Bevor der Code einer Anwendung geändert werden kann, z.B., um ein neues Feature zu implementieren, muss beim Test-driven Development zunächst ein Unit Test geschrieben werden.
Dieser Test beschreibt so minimal wie möglich die fehlende Funktionalität und gibt so z.B. die öffentliche Schnittstelle für neue Klassen und Funktionen vor. Wichtig ist, dass der neue Test fehlschlägt, z.B. weil es die verwendete Funktion noch nicht gibt oder sie die getestete Funktionalität nicht vollständig implementieren.
Erst dann sollte der eigentliche Code der Anwendung solange angepasst werden, bis der neue Test sowie alle evtl. schon vorhandenen Tests erfolgreich ausgeführt werden können.
Danach können weitere Tests geschrieben werden, die z.B. weitere Eingabewerte für die Funktion berücksichtigen. Dieser Kreislauf wird dann solange wiederholt, bis man sicher ist, dass die neue Funktion einwandfrei funktioniert.
Sobald die neue Funktion fertig-implementiert ist, kann man den Code noch – sofern notwendig – aufräumen. Dank der Unit Tests wird beim Refactoring und auch bei späteren Änderungen am Code vermieden, dass sich wieder Bugs einschleichen, wodurch weniger Zeit benötigt wird, den Code zu debuggen.