Einführung
In diesem Lab lernen Sie, wie Sie das eingebaute unittest-Modul von Python verwenden. Dieses Modul bietet ein Framework zum Organisieren und Ausführen von Tests, was ein entscheidender Bestandteil der Softwareentwicklung ist, um sicherzustellen, dass Ihr Code korrekt funktioniert.
Sie werden auch lernen, grundlegende Testfälle zu erstellen und auszuführen sowie auf erwartete Fehler und Ausnahmen zu testen. Das unittest-Modul vereinfacht den Prozess der Erstellung von Test-Suiten, des Ausführens von Tests und der Überprüfung der Ergebnisse. Die Datei teststock.py wird während dieses Labs erstellt.
Erstellen Ihres ersten Unit-Tests
Python's unittest-Modul ist ein leistungsstarkes Werkzeug, das eine strukturierte Möglichkeit bietet, Tests zu organisieren und auszuführen. Bevor wir uns mit dem Schreiben unseres ersten Unit-Tests befassen, sollten wir einige Schlüsselkonzepte verstehen. Test-Fixtures sind Methoden wie setUp und tearDown, die helfen, die Umgebung vor einem Test vorzubereiten und sie danach aufzuräumen. Testfälle sind einzelne Testeinheiten, Test-Suiten sind Sammlungen von Testfällen, und Test-Runner sind für die Ausführung dieser Tests und die Präsentation der Ergebnisse verantwortlich.
In diesem ersten Schritt werden wir eine grundlegende Testdatei für die Stock-Klasse erstellen, die bereits in der Datei stock.py definiert ist.
- Zunächst öffnen wir die Datei
stock.py. Dies hilft uns, dieStock-Klasse zu verstehen, die wir testen werden. Indem wir uns den Code instock.pyansehen, können wir sehen, wie die Klasse strukturiert ist, welche Attribute sie hat und welche Methoden sie bereitstellt. Um den Inhalt der Dateistock.pyanzuzeigen, führen Sie den folgenden Befehl in Ihrem Terminal aus:
cat stock.py
- Jetzt ist es an der Zeit, eine neue Datei mit dem Namen
teststock.pymit Ihrem bevorzugten Texteditor zu erstellen. Diese Datei wird unsere Testfälle für dieStock-Klasse enthalten. Hier ist der Code, den Sie in der Dateiteststock.pyschreiben müssen:
## teststock.py
import unittest
import stock
class TestStock(unittest.TestCase):
def test_create(self):
s = stock.Stock('GOOG', 100, 490.1)
self.assertEqual(s.name, 'GOOG')
self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1)
if __name__ == '__main__':
unittest.main()
Lassen Sie uns die Schlüsselkomponenten dieses Codes analysieren:
import unittest: Diese Zeile importiert dasunittest-Modul, das die notwendigen Werkzeuge und Klassen zum Schreiben und Ausführen von Tests in Python bereitstellt.import stock: Dies importiert das Modul, das unsereStock-Klasse enthält. Ohne diesen Import könnten wir dieStock-Klasse in unserem Testcode nicht zugreifen.class TestStock(unittest.TestCase): Wir erstellen eine neue Klasse namensTestStock, die vonunittest.TestCaseerbt. Dies macht unsereTestStock-Klasse zu einer Testfallklasse, die mehrere Testmethoden enthalten kann.def test_create(self): Dies ist eine Testmethode. Imunittest-Framework müssen alle Testmethoden mit dem Präfixtest_beginnen. Diese Methode erstellt eine Instanz derStock-Klasse und verwendet dann dieassertEqual-Methode, um zu überprüfen, ob die Attribute derStock-Instanz den erwarteten Werten entsprechen.assertEqual: Dies ist eine Methode, die von derTestCase-Klasse bereitgestellt wird. Sie überprüft, ob zwei Werte gleich sind. Wenn sie nicht gleich sind, schlägt der Test fehl.unittest.main(): Wenn dieses Skript direkt ausgeführt wird, wirdunittest.main()alle Testmethoden in derTestStock-Klasse ausführen und die Ergebnisse anzeigen.
- Nachdem Sie den Code in der Datei
teststock.pygeschrieben haben, speichern Sie ihn. Führen Sie dann den folgenden Befehl in Ihrem Terminal aus, um den Test auszuführen:
python3 teststock.py
Sie sollten eine Ausgabe ähnlich der folgenden sehen:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Der einzelne Punkt (.) in der Ausgabe gibt an, dass ein Test erfolgreich abgeschlossen wurde. Wenn ein Test fehlschlägt, sehen Sie anstelle des Punkts ein F, zusammen mit detaillierten Informationen darüber, was im Test schief gelaufen ist. Diese Ausgabe hilft Ihnen, schnell zu erkennen, ob Ihr Code wie erwartet funktioniert oder ob es Probleme gibt, die behoben werden müssen.
Erweitern Ihrer Testfälle
Nachdem Sie nun einen grundlegenden Testfall erstellt haben, ist es an der Zeit, Ihren Testumfang zu erweitern. Das Hinzufügen weiterer Tests hilft Ihnen, die restliche Funktionalität der Stock-Klasse abzudecken. Auf diese Weise können Sie sicherstellen, dass alle Aspekte der Klasse wie erwartet funktionieren. Wir werden die TestStock-Klasse ändern, um Tests für mehrere Methoden und Eigenschaften hinzuzufügen.
- Öffnen Sie die Datei
teststock.py. Innerhalb derTestStock-Klasse werden wir einige neue Testmethoden hinzufügen. Diese Methoden werden verschiedene Teile derStock-Klasse testen. Hier ist der Code, den Sie hinzufügen müssen:
def test_create_keyword_args(self):
s = stock.Stock(name='GOOG', shares=100, price=490.1)
self.assertEqual(s.name, 'GOOG')
self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1)
def test_cost(self):
s = stock.Stock('GOOG', 100, 490.1)
self.assertEqual(s.cost, 49010.0)
def test_sell(self):
s = stock.Stock('GOOG', 100, 490.1)
s.sell(20)
self.assertEqual(s.shares, 80)
def test_from_row(self):
row = ['GOOG', '100', '490.1']
s = stock.Stock.from_row(row)
self.assertEqual(s.name, 'GOOG')
self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1)
def test_repr(self):
s = stock.Stock('GOOG', 100, 490.1)
self.assertEqual(repr(s), "Stock('GOOG', 100, 490.1)")
def test_eq(self):
s1 = stock.Stock('GOOG', 100, 490.1)
s2 = stock.Stock('GOOG', 100, 490.1)
self.assertEqual(s1, s2)
Schauen wir uns genauer an, was jeder dieser Tests tut:
test_create_keyword_args: Dieser Test prüft, ob Sie einStock-Objekt mithilfe von Schlüsselwortargumenten erstellen können. Er überprüft, ob die Attribute des Objekts korrekt gesetzt sind.test_cost: Dieser Test prüft, ob diecost-Eigenschaft einesStock-Objekts den korrekten Wert zurückgibt, der als Anzahl der Aktien multipliziert mit dem Preis berechnet wird.test_sell: Dieser Test prüft, ob diesell()-Methode einesStock-Objekts die Anzahl der Aktien korrekt aktualisiert, nachdem einige verkauft wurden.test_from_row: Dieser Test prüft, ob die Klassenmethodefrom_row()eine neueStock-Instanz aus einer Datenzeile erstellen kann.test_repr: Dieser Test prüft, ob die__repr__()-Methode einesStock-Objekts die erwartete Zeichenkettenrepräsentation zurückgibt.test_eq: Dieser Test prüft, ob die__eq__()-Methode zweiStock-Objekte korrekt vergleicht, um festzustellen, ob sie gleich sind.
- Nachdem Sie diese Testmethoden hinzugefügt haben, speichern Sie die Datei
teststock.py. Führen Sie dann die Tests erneut aus, indem Sie den folgenden Befehl in Ihrem Terminal ausführen:
python3 teststock.py
Wenn alle Tests erfolgreich sind, sollten Sie eine Ausgabe wie diese sehen:
......
----------------------------------------------------------------------
Ran 7 tests in 0.001s
OK
Die sieben Punkte in der Ausgabe repräsentieren jeden Test. Jeder Punkt gibt an, dass ein Test erfolgreich abgeschlossen wurde. Wenn Sie also sieben Punkte sehen, bedeutet dies, dass alle sieben Tests bestanden wurden.
Testen auf Ausnahmen
Das Testen ist ein entscheidender Teil der Softwareentwicklung, und ein wichtiger Aspekt davon ist es, sicherzustellen, dass Ihr Code Fehlerbedingungen richtig behandeln kann. In Python bietet das unittest-Modul eine bequeme Möglichkeit, zu testen, ob bestimmte Ausnahmen (Exceptions) wie erwartet ausgelöst werden.
- Öffnen Sie die Datei
teststock.py. Wir werden einige Testmethoden hinzufügen, die darauf ausgelegt sind, auf Ausnahmen zu prüfen. Diese Tests helfen uns, sicherzustellen, dass unser Code richtig reagiert, wenn er ungültige Eingaben erhält.
def test_shares_type(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(TypeError):
s.shares = '50'
def test_shares_value(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(ValueError):
s.shares = -50
def test_price_type(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(TypeError):
s.price = '490.1'
def test_price_value(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(ValueError):
s.price = -490.1
def test_attribute_error(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(AttributeError):
s.share = 100 ## 'share' is incorrect, should be 'shares'
Jetzt verstehen wir, wie diese Ausnahmetests funktionieren.
- Die Anweisung
with self.assertRaises(ExceptionType):erstellt einen Kontextmanager. Dieser Kontextmanager prüft, ob der Code innerhalb deswith-Blocks die angegebene Ausnahme auslöst. - Wenn die erwartete Ausnahme innerhalb des
with-Blocks ausgelöst wird, besteht der Test. Dies bedeutet, dass unser Code die ungültige Eingabe richtig erkennt und die entsprechende Fehlermeldung auslöst. - Wenn keine Ausnahme ausgelöst wird oder eine andere Ausnahme ausgelöst wird, scheitert der Test. Dies zeigt an, dass unser Code die ungültige Eingabe möglicherweise nicht wie erwartet behandelt.
Diese Tests sind darauf ausgelegt, die folgenden Szenarien zu überprüfen:
- Das Setzen des
shares-Attributs auf eine Zeichenkette sollte einenTypeErrorauslösen, dashareseine Zahl sein sollte. - Das Setzen des
shares-Attributs auf eine negative Zahl sollte einenValueErrorauslösen, da die Anzahl der Aktien nicht negativ sein kann. - Das Setzen des
price-Attributs auf eine Zeichenkette sollte einenTypeErrorauslösen, dapriceeine Zahl sein sollte. - Das Setzen des
price-Attributs auf eine negative Zahl sollte einenValueErrorauslösen, da der Preis nicht negativ sein kann. - Der Versuch, ein nicht existierendes Attribut
share(beachten Sie das fehlende 's') zu setzen, sollte einenAttributeErrorauslösen, da der korrekte Attributnamesharesist.
- Nachdem Sie diese Testmethoden hinzugefügt haben, speichern Sie die Datei
teststock.py. Führen Sie dann alle Tests aus, indem Sie den folgenden Befehl in Ihrem Terminal ausführen:
python3 teststock.py
Wenn alles richtig funktioniert, sollten Sie eine Ausgabe sehen, die anzeigt, dass alle 12 Tests bestanden wurden. Die Ausgabe sieht wie folgt aus:
............
----------------------------------------------------------------------
Ran 12 tests in 0.002s
OK
Die zwölf Punkte repräsentieren alle Tests, die Sie bisher geschrieben haben. Es gab 7 Tests aus dem vorherigen Schritt, und wir haben gerade 5 neue hinzugefügt. Diese Ausgabe zeigt, dass Ihr Code Ausnahmen wie erwartet behandelt, was ein gutes Zeichen für ein gut getestetes Programm ist.
Ausführen ausgewählter Tests und Verwendung der Testermittlung
Das unittest-Modul in Python ist ein leistungsstarkes Werkzeug, das es Ihnen ermöglicht, Ihren Code effektiv zu testen. Es bietet mehrere Möglichkeiten, bestimmte Tests auszuführen oder automatisch alle Tests in Ihrem Projekt zu finden und auszuführen. Dies ist sehr nützlich, da es Ihnen hilft, sich während des Testens auf bestimmte Teile Ihres Codes zu konzentrieren oder die gesamte Testsuite Ihres Projekts schnell zu überprüfen.
Ausführen bestimmter Tests
Manchmal möchten Sie möglicherweise nur bestimmte Testmethoden oder Testklassen anstelle der gesamten Testsuite ausführen. Dies können Sie erreichen, indem Sie die Musteroption (pattern option) mit dem unittest-Modul verwenden. Dies gibt Ihnen mehr Kontrolle darüber, welche Tests ausgeführt werden, was hilfreich sein kann, wenn Sie einen bestimmten Teil Ihres Codes debuggen.
- Um nur die Tests auszuführen, die sich auf das Erstellen eines Stock-Objekts beziehen:
python3 -m unittest teststock.TestStock.test_create
In diesem Befehl teilt python3 -m unittest Python mit, das unittest-Modul auszuführen. teststock ist der Name der Testdatei, TestStock ist der Name der Testklasse und test_create ist die spezifische Testmethode, die wir ausführen möchten. Durch Ausführen dieses Befehls können Sie schnell überprüfen, ob der Code, der sich auf das Erstellen eines Stock-Objekts bezieht, wie erwartet funktioniert.
- Um alle Tests in der
TestStock-Klasse auszuführen:
python3 -m unittest teststock.TestStock
Hier lassen wir den Namen der spezifischen Testmethode weg. Dieser Befehl führt also alle Testmethoden innerhalb der TestStock-Klasse in der teststock-Datei aus. Dies ist nützlich, wenn Sie die Gesamtfunktionalität der Testfälle für das Stock-Objekt überprüfen möchten.
Verwendung der Testermittlung
Das unittest-Modul kann automatisch alle Testdateien in Ihrem Projekt finden und ausführen. Dies erspart Ihnen die Mühe, jede Testdatei manuell anzugeben, die ausgeführt werden soll, insbesondere in größeren Projekten mit vielen Testdateien.
- Benennen Sie die aktuelle Datei um, um dem Namensmuster für die Testermittlung zu folgen:
mv teststock.py test_stock.py
Der Testermittlungsmechanismus in unittest sucht nach Dateien, die dem Namensmuster test_*.py folgen. Indem wir die Datei in test_stock.py umbenennen, erleichtern wir es dem unittest-Modul, die Tests in dieser Datei zu finden und auszuführen.
- Führen Sie die Testermittlung aus:
python3 -m unittest discover
Dieser Befehl teilt dem unittest-Modul mit, automatisch alle Testdateien zu finden und auszuführen, die dem Muster test_*.py im aktuellen Verzeichnis entsprechen. Es wird durch das Verzeichnis suchen und alle gefundenen Testfälle in den passenden Dateien ausführen.
- Sie können auch ein Verzeichnis angeben, in dem nach Tests gesucht werden soll:
python3 -m unittest discover -s . -p "test_*.py"
Dabei bedeuten:
-s .gibt das Verzeichnis an, in dem die Ermittlung beginnen soll (in diesem Fall das aktuelle Verzeichnis). Der Punkt (.) repräsentiert das aktuelle Verzeichnis. Sie können dies in einen anderen Verzeichnispfad ändern, wenn Sie in einem anderen Ort nach Tests suchen möchten.-p "test_*.py"ist das Muster, nach dem Testdateien übereinstimmen müssen. Dies stellt sicher, dass nur Dateien mit Namen, die mittest_beginnen und die.py-Erweiterung haben, als Testdateien betrachtet werden.
Sie sollten sehen, dass alle 12 Tests ausgeführt und bestanden werden, genau wie zuvor.
- Benennen Sie die Datei wieder in den ursprünglichen Namen um, um die Konsistenz mit dem Lab zu gewährleisten:
mv test_stock.py teststock.py
Nachdem Sie die Testermittlung ausgeführt haben, benennen we wieder die Datei in ihren ursprünglichen Namen um, um die Lab-Umgebung konsistent zu halten.
Durch die Verwendung der Testermittlung können Sie alle Tests in einem Projekt einfach ausführen, ohne jede Testdatei einzeln angeben zu müssen. Dies macht den Testprozess effizienter und fehleranfälliger.
Zusammenfassung
In diesem Lab haben Sie gelernt, wie Sie das unittest-Modul von Python verwenden, um automatisierte Tests zu erstellen und auszuführen. Sie haben einen grundlegenden Testfall erstellt, indem Sie die unittest.TestCase-Klasse erweitert haben, Tests geschrieben, um die normale Funktionsweise der Methoden und Eigenschaften einer Klasse zu überprüfen, und Tests erstellt, um auf geeignete Ausnahmen (Exceptions) unter Fehlersituationen zu prüfen. Sie haben auch gelernt, wie Sie bestimmte Tests ausführen und die Testermittlung (test discovery) nutzen.
Das Unit-Testing ist eine grundlegende Fähigkeit in der Softwareentwicklung, die die Zuverlässigkeit und Korrektheit des Codes gewährleistet. Das Schreiben umfassender Tests hilft, Fehler frühzeitig zu erkennen und gibt Ihnen Vertrauen in das Verhalten Ihres Codes. Wenn Sie Python-Anwendungen entwickeln, sollten Sie einen testgetriebenen Entwicklungsansatz (Test-Driven Development, TDD) in Betracht ziehen und Tests schreiben, bevor Sie die Funktionalität implementieren, um einen robusteren und wartbareren Code zu erhalten.