Seite wählen

NETWAYS Blog

coverage.py in Jenkins integrieren

Nachdem bereits letzte Woche Gunnar etwas zu code coverage geschrieben hat werde ich jetzt noch einmal nachlegen, mich jedoch auf coverage.py und dessen Nutzung sowie die Integration in Jenkins beschränken.
Was ist coverage.py?
coverage.py ist ein Tool um für in Python geschriebenen Quellcode coverage reports zu generieren. Aber zuerst einmal müssen ein paar Informationen generiert werden, damit überhaupt irgendetwas visuell dargestellt werden kann:
coverage run python-script
Reports werden dann folgendermaßen generiert:
coverage report # Text-basierter Report in der Konsole
coverage html -d ziel-verzeichnis # html Report mit im Quellcode hervergehobenen Zeilen
coverage xml -o xml-datei # xml Report für die Weiterverarbeitung in anderen Systemen
Das ganze geht natürlich auch in Verbindung mit nosetests. Details dazu könnt ihr hier finden.
Integration in Jenkins
Um nun coverage reports in Jenkins für das eigene Projekt zu generieren greifen wir selbstverständlich auf coverage.py zurück. Um das zu realisieren bietet sich „Execute shell“ als build step an in welchem wir oben angegebene Befehle ausführen lassen:
coverage run python-script
coverage xml # Output landet per default in coverage.xml
Dann legt man eine post-build action an, die sich „Publish Cobertura Coverage Report“ nennt und gibt dort bei „Cobertura xml report pattern“ den Pfad zu der vom build step generierten xml Datei an. (**/coverage.xml, falls die Datei direkt im workspace liegt.)
Soweit so gut. Wenn nun ein Build ausgeführt wird, hat man am Ende einen coverage report in Jenkins, der jedoch keinerlei Details dazu aufführt welche Zeilen im Quellcode denn nun genau betroffen sind. Zu beurteilen woran das liegt, maße ich mir hier einfach mal nicht an und gebe nur einen kleinen Hinweis wie dieses Problem mit einer kleinen Erweiterung des build steps zu lösen ist:
sed -i -e 's??ein/relativer/pfad/zum/quellcode?' coverage.xml
sed -i -e 's?filename="'$WORKSPACE'/ein/relativer/pfad/zum/quellcode/?filename="?' coverage.xml
Wobei hier „ein/relativer/pfad/zum/quellcode“ zu ersetzen ist. Zu beachten ist hierbei, dass es sich tatsächlich um einen relativen Pfad handeln muss, ausgehend vom workspace. Beim nächsten Build gibts dann auch hervorgehobene Zeilen im Quellcode. 🙂
Zu guter letzt noch ein Protip:
Um coverage.py dazu zu bringen branch coverage (conditionals usw.) zu messen muss eine spezielle Option angegeben werden:
coverage run --branch python-script
Damit das auch mit nosetests funktioniert, bedarf es erneut eines kleinen Tricks:
touch .coveragerc
echo "# .coveragerc to control coverage.py\n\n[run]\nbranch=True" > .coveragerc
Das muss im selben Verzeichnis ausgeführt werden in dem auch coverage.py selbst ausgeführt werden wird.
Und nun viel Spaß mit den vielen bunten Trends und Quellcodes! 😀

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

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.