Python Code Coverage
Python ist eine der derzeit beliebtesten Programmiersprachen. Aufgrund seiner Allgemeingültigkeit findet Python Anwendung in verschiedenen Anwendungsfällen der Softwareentwicklung, vom einfachen Skripting über Webserver bis hin zu Frameworks wie Django.
Wie bei anderen Programmiersprachen bleibt jedoch auch bei Python das Testen einer der wichtigsten Aspekte der Softwareentwicklung.
In diesem Beitrag sehen wir uns einige Tools an, mit denen man die Testfallabdeckung für Python-Code messen und schreiben kann.
Unittest
Die Python-Standardbibliothek ist mit einem Modul namens unittest vorinstalliert. Inspiriert von JUnit und anderen Unit-Testing-Frameworks großer Programmiersprachen ist unittest ein Test-Framework, mit dem man Tests automatisieren, gemeinsamen Setup- und Shutdown-Code für Tests einrichten kann und vieles mehr.
Eine der wichtigen Funktionen von unittest ist Test Fixture, d.h. das Setup, das für die Ausführung eines oder mehrerer Tests benötigt wird, sowie alle damit verbundenen Bereinigungsaktionen. Mit Text Fixture können Aktivitäten wie das Erstellen von temporären oder Proxy-Datenbanken, Verzeichnissen oder das Starten eines Server-Prozesses an einer einzigen Stelle erledigt werden.
Lassen Sie uns einige Beispiel-Testfälle nehmen und sehen, wie sie mit unittest implementiert werden:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual(‚foo‘.upper(), ‚FOO‘)
def test_isupper(self):
self.assertTrue(‚FOO‘.isupper())
self.assertFalse(‚Foo‘.isupper())
def test_split(self):
s = ‚hello world‘
self.assertEqual(s.split(), )
# prüfen, dass s.split fehlschlägt, wenn das Trennzeichen kein String ist
mit self.assertRaises(TypeError):
s.split(2)
if __name__ == ‚__main__‘:
unittest.main()
Erstellen Sie einen Testfall, indem Sie unittest.TestCase unterklassifizieren. Anschließend können Sie einzelne Tests mit Methoden definieren. Beachten Sie, dass die Namen der Testfälle mit dem Wort test beginnen sollten. Diese Namenskonvention informiert den Test Runner darüber, welche Methoden Tests darstellen.
Der Test Runner ist die Komponente, die die Ausführung von Tests orchestriert und dem Benutzer das Ergebnis zur Verfügung stellt. Seine Implementierung variiert und kann eine grafische Schnittstelle, eine textuelle Schnittstelle oder einen speziellen Wert zurückgeben, um die Ergebnisse der Testausführung anzuzeigen.
Pytest
Pytest ist ein Python-Testframework von einem Drittanbieter. Es zielt darauf ab, ein Framework zur Verfügung zu stellen, um Ihre Tests effizient zu schreiben, indem es alle Overheads für die Erstellung von Tests entfernt. Pytest wird von Python 2.7, 3.4, 3.5, 3.6, Jython, PyPy-2.3 unter Unix/Posix und Windows unterstützt.
Lassen Sie uns einen Blick darauf werfen, wie Sie mit Pytest beginnen können.Laden Sie zunächst die neueste Version herunter und installieren Sie sie über pip:
Sie können die installierte Version überprüfen, indem Sie:
Nun lassen Sie uns eine Beispielfunktion und den dazugehörigen Testfall nehmen.
def func(x):
return x + 1def test_answer():
assert func(3) == 5
Die Funktion func nimmt eine Eingabe x und gibt einen Wert x + 1 zurück. Im Testfall wird überprüft, ob die Funktion func die Eingabe 3 annimmt und 5 zurückgibt. Es wird erwartet, dass dieser Testfall fehlschlägt. Um den Test auszuführen, geben Sie einfach pytest in das Verzeichnis mit der Datei test_sample.py ein.
$ pytest
=========================== test session starts ============================
platform linux – Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 itemtest_sample.py F ================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
========================= 1 failed in 0.12 seconds =========================
Coverage.py
Coverage.py ist eines der beliebtesten Code Coverage Tools für Python. Es verwendet Code-Analyse-Tools und Tracing-Hooks, die in der Python-Standardbibliothek enthalten sind, um die Abdeckung zu messen. Es läuft auf den Hauptversionen von CPython, PyPy, Jython und IronPython. Sie können Coverage.py sowohl mit Unittest als auch mit Pytest verwenden.
Sie können entweder die neueste Version von Coverage herunterladen und manuell installieren, oder Sie können es mit pip as installieren:
Nun führen Sie Ihr Programm mit coverage as
Als Nächstes führen Sie
Hier ist ein Beispiel für die Ausgabe von Abdeckungsdaten
Name Stmts Miss Cover Missing
——————-
my_program.py 20 4 80% 33-35, 39
my_other_module.py 56 6 89% 17-23
——————-
TOTAL 76 10 87%
Bericht in HTML-Datei generieren:
$ coverage html
Dies ist ein Beispiel-HTML-Bericht, wie er von Coverage.py generiert wurde. Er enthält Module, Anweisungen, fehlende, ausgeschlossene, Verzweigungen, partielle und Abdeckung.
Pytest-cov
Pytest-cov ist ein Python-Plugin zur Erstellung von Abdeckungsberichten. Zusätzlich zu den Funktionen, die vom Befehl coverage unterstützt werden, unterstützt es auch zentralisierte und verteilte Tests. Es unterstützt auch die Abdeckung von Unterprozessen.
Sobald Sie mit Pytest die erforderlichen Testfälle geschrieben haben, können Sie Pytest-cov verwenden, um alle Tests auszuführen und die Abdeckung zu melden.
Um loszulegen, installieren Sie Pytest-cov wie folgt:
Zentrales Testen
Zentrales Testen meldet die kombinierte Abdeckung des Hauptprozesses und aller seiner Unterprozesse. Sie können zentralisierte Tests durchführen mit:
Verteilte Tests
Installieren Sie Pytest-xdist, für verteilte Systemunterstützung:
Verteilte Tests können in zwei Modi durchgeführt werden, dist auf load und each gesetzt. Wenn auf load gesetzt, wird die kombinierte Abdeckung aller Slaves während des verteilten Testens gemeldet. Die Slaves können über eine beliebige Anzahl von Hosts verteilt sein, und jeder Slave kann sich an einem beliebigen Ort im Dateisystem befinden. Für jeden Slave werden die Unterprozesse gemessen.
Für verteilte Tests in jedem Modus gibt pytest-cov auch die kombinierte Abdeckung aller Slaves an. Da jeder Slave alle Tests ausführt, ermöglicht dies die Erstellung eines kombinierten Abdeckungsberichts für mehrere Umgebungen
Zusammenfassung
In diesem Beitrag haben wir verschiedene Python-Einheitstests und Code-Abdeckungs-Frameworks kennengelernt. Während diese Frameworks den Testprozess vereinfachen, müssen Sie die Tests immer noch schreiben. Hier sind einige Best Practices, die beim Schreiben von Unit-Tests zu beachten sind.
- Verwenden Sie lange, beschreibende Namen. Dadurch werden oft Bezeichnungen in Testmethoden überflüssig.
- Tests sollten isoliert sein. Sie sollten nicht mit einer echten Datenbank oder einem Netzwerk interagieren. Verwenden Sie eine separate Testdatenbank, die abgerissen wird oder Scheinobjekte verwendet.
- Konzentrieren Sie sich auf ein winziges Stück Funktionalität.
- Sollte schnell sein, aber ein langsamer Test ist besser als kein Test.
- Es ist oft sinnvoll, eine Testfallklasse für eine einzelne Klasse oder ein Modell zu haben.