[gelöst] Python3.7 - unittest: tearDown auch bei Fehlern

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
buhtz
Beiträge: 1205
Registriert: 04.12.2015 17:54:49
Kontaktdaten:

[gelöst] Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von buhtz » 07.05.2020 13:36:09

Ich nutze Debian stable und derzeit daher auf Python 3.7.3 festgenagelt. Erst Python 3.8 und 3.9 bieten eine hauseigene Lösung für mein Problem.

Problem: Wenn ein unittest.TestCase einen Fehler wirft, wird die tearDownClass() oder tearDownModule() nicht mehr aufgerufen. D.h. im Falle eines Fehlers, habe ich keine Möglichkeit aufzuräumen. Sicherlich bin ich nicht der Erste mit so einem Problem. Wie haben die Profis das bisher gelöst? Oder gibt es für meinen Use case einen ganz anderen Ansatz?

Konkret generiere ich für jede TestCase Instanz ein eigenes temporäres Nutzerprofil - d.h. Konfigurationsdateien, Default-Testdaten, etc. Die Test-Methoden arbeiten dann damit und verändern diese Daten im Rahmen der Tests auch. Wird dann am Ende alles wieder gelöscht (also Dateien/Ordner werden gelöscht) - weil ja sonst meine Platte voll läuft und auch die nächsten TestCase mit frischen Daten arbeiten sollen.

Wie kann ich das lösen?

TestCase.addCleanup() scheint sich nur auf setUp() und tearDown() zu beziehen - also wird nach jeder einzelnen Test-Methode aufgerufen. Ich möchte das CeanUp aber erst haben, wenn alle Test-Methoden einer Test-Klasse abgearbeitet wurden (oder Fehler aufgetaucht sind).
Zuletzt geändert von buhtz am 09.05.2020 13:08:15, insgesamt 1-mal geändert.
Debian 11 & 12; Desktop-PC, Headless-NAS, Raspberry Pi 4
Teil des Upstream Betreuer Teams von Back In Time (Debianbackintime)

cronoik
Beiträge: 2049
Registriert: 18.03.2012 21:13:42
Lizenz eigener Beiträge: GNU Free Documentation License

Re: Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von cronoik » 07.05.2020 14:27:20

Hi,

ich kann dir momentan keinen Vorschlag bieten. Wuerde mir die Sache allerdings gern anschauen. Falls es nicht zu viel Arbeit macht, kannst dann bitte mal ein kleines Beispiel posten (vielleicht Datei anlegen+etwas reinschreiben).

P.S.: Eine Parallelinstallation einer anderen Pythonversion via pyenv oder conda ist fuer dich keine Option?
Hilf mit unser Wiki zu verbessern!

Benutzeravatar
bmario
Beiträge: 1257
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von bmario » 07.05.2020 20:43:21

Hi.

Also ich persönlich benutze pytest für meine Tests. Was man in unittest mit Setup und tearDown macht, erledigt man in pytest mit fixtures. Du benutzt dann in dem fixture einfach yield und schreibst den tearDown Code dahinter. Zusammen mit dem passenden scope für das fixture kannst du alles abbilden.

https://docs.pytest.org/en/latest/fixtu ... rdown-code
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

buhtz
Beiträge: 1205
Registriert: 04.12.2015 17:54:49
Kontaktdaten:

Re: Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von buhtz » 09.05.2020 09:32:29

cronoik hat geschrieben: ↑ zum Beitrag ↑
07.05.2020 14:27:20
ich kann dir momentan keinen Vorschlag bieten. Wuerde mir die Sache allerdings gern anschauen. Falls es nicht zu viel Arbeit macht, kannst dann bitte mal ein kleines Beispiel posten (vielleicht Datei anlegen+etwas reinschreiben).
Danke für das Angebot.
Während ich überlegt, wie ich das als Minimal Working Example darstellen kann, viel mir auf, dass ich evtl. grundsätzlich am Design und der Herangehensweise etwas ändern sollte. Dann tappe ich evtl. auch nicht mehr in dieses Problem. Nebenbei bin ich auch gerade in einer umfassenden Refactoring-Phase (also großer Umbau).
Aktuell nutze ich setup und teardown auf Modulebene - da teardown hier auch bei Fehlern aufgerufen wird. Ob das langfristig sinnvoll ist, wird sich zeigen. Evtl. komme ich nochmal auf dein Angebot zurück.
cronoik hat geschrieben: ↑ zum Beitrag ↑
07.05.2020 14:27:20
P.S.: Eine Parallelinstallation einer anderen Pythonversion via pyenv oder conda ist fuer dich keine Option?
Ne, solche Tweaks führen (erfahrungsgemäß) bei mir langfristig immer ins Chaos, weil ich vergesse haben, dass ich das überhaupt gemacht habe usw. Sitze zu wenig kontinuierlich an der Kiste und den Projekten, um das im Blick zu haben. Auserdem ist Debian stable mein definierter Standard - alles was da nicht drin ist wird von mir ignoriert - einfach nur weil es einfacher für mich ist. ;) Mein "Workload" (bzw. die Ressourcen) bewegen sich hier auf Feierabend-plus-Kleinkinder-Hobby-Niveau - daher versuche ich hier kleine Brötchen zu backen. ;)
Debian 11 & 12; Desktop-PC, Headless-NAS, Raspberry Pi 4
Teil des Upstream Betreuer Teams von Back In Time (Debianbackintime)

Benutzeravatar
SubOptimal
Beiträge: 1709
Registriert: 10.01.2005 23:25:46
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: bei Frankfurt

Re: Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von SubOptimal » 09.05.2020 12:08:18

Hi @buhtz,

vielleicht liegt das Problem auch woanders (kann es aber auch falsch herausgelesen haben)

Folgendes Mini-Besipiel für "tearDownClass"

Code: Alles auswählen

#!/usr/bin/env python3
import unittest

class TestOpenFileChunk(unittest.TestCase):
    def setUp(self):
        print("setUp")

    def tearDown(self):
        print("tearDown")

    def test_success(self):
        print("test_success")

    def test_fail(self):
        print("test_fail")
        print("something {}".format(res))

if __name__ == '__main__':
    unittest.main()
liefert auf Buster

Code: Alles auswählen

$ ./test.py
setUp
test_fail
tearDown
EsetUp
test_success
tearDown
.tearDownClass

======================================================================
ERROR: test_fail (__main__.SomeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test.py", line 21, in test_fail
    print("something {}".format(res))
NameError: name 'res' is not defined

----------------------------------------------------------------------
Ran 2 tests in 0.014s

FAILED (errors=1)
Schaut für mich so aus, dass "tearDownClass" ausgeführt wird.

mit Gruß
SubOptimal

buhtz
Beiträge: 1205
Registriert: 04.12.2015 17:54:49
Kontaktdaten:

Re: Python3.7 - unittest: tearDown auch bei Fehlern

Beitrag von buhtz » 09.05.2020 12:33:39

Ähm... Ich glaube ich bringe auch gerade etwas durcheinander.
Ich denke es ist ein Unterschied, ob ein Test fehl schlägt, oder ob ein Fehler in der setUp-Methode (egal ob Objekt, Klasse oder Modul) stattfindet. Bin verwirrt....

Fehler in setUp
Soweit ich das jetzt mit einem Kurztest (python 3.7.3) prüfen konnte, wird in allen drei Varienten (Objekt, Klasse, Modul) tearDown nie ausgeführt, wenn in der setUp Methode ein Fehler passiert.

Fehlgeschlagener Test
Modul-Ebene: tearDown wird trotzdem ausgeführt.
Klassen-Ebene: tearDown wird trotzdem ausgeführt.
Objekt-Ebene: tearDown wird trotzdem ausgeführt.

Hab ich das jetzt richtig auf dem Schirm?
Ich denke ich hab das vermischt. Sorry und danke für das auf die richtige Fährte bringen.

Wo war jetzt eigentlich nochmal mein Problem?
Es gibt kein addCleanup() auf Klassen oder Modul-Ebene - jedenfalls in der aktuellen Debian stable Python Version 3.7.3. (Ab Version 3.8 gibt es Cleanup auch auf Klassen-Ebene und auf Modul-Ebene.) Cleanup-Methoden werden auch abgearbeitet, wenn tearDown nicht aufgerufen wird.

Also Frage nochmal neu formuliert: Wie kann ich ein CleanUp machen, wenn tearDown() auf Klassen oder Modul-Ebene nicht aufgerufen wird? ;)
Spontane Idee: Ich könnte im Scope des Moduls ein Objekt erzeugen, dass die Ressourcen (z.B. offene Config-Dateien, Datenbanken-Verbindungen) hält und im __del__() wieder sauber schließt und löscht. Problem ist doch aber immer, dass ich nie sicher sein kann, wann der GarbeCollector den destructor wirlklich aufruft. Da kann die nächste Test-Klasse bzw. das Test-Modul schon laufen, wärend die Ressourcen vom vorherigen Test-Modul noch belegt sind. Genau das möchte ich vermeiden.

Das bringt mich wieder zurück zur Aufgabenstellen ein Minimal Working Example beizusteuern. Eigentlich ist das, wass ich hier will gar nicht nötig.
Wenn setUp fehlschlägt, bekomme ich das ja eigentlich mit und kann mir dann denken, dass ich dann die temporären Dateien manuell löschen muss. Wie oft kommt es den vor, dass setUp einen Fehler produziert?
Ursache war nämlich, dass ich zum Ausführen der Tests green verwendet hatte und hier in einen Bug gelaufen bin, der aber sehr schnell behoben wurde: Fehler in setUp wurden auf Klassen und Modul-Ebene tatsächlich nicht angezeigt.
Debian 11 & 12; Desktop-PC, Headless-NAS, Raspberry Pi 4
Teil des Upstream Betreuer Teams von Back In Time (Debianbackintime)

Antworten