wie geht Pytest auf exception-handler ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
HeinzBacker
User
Beiträge: 19
Registriert: Dienstag 10. März 2020, 20:20

Grüß dich!

Ich will gerade einen ersten Pytest ausführen und zwar soll auf eine ungültige Datei beim Dateiöffnen geprüft werden.
Normalerweise wird die FileNotFoundError-Exception geworfen, aber der Test schlägt trotzdem fehl.
Ich würde gern verstehen, warum es nicht geht (unten ist die Ausgabe).
Vielen Dank schonmal für Tipps!



Programm code:
file_handler.py

Code: Alles auswählen

class Filehandler():
    def __init__(self):
        pass

    def read_file(filename_str):
        lines = []
        try:
            with open(filename_str, 'r', encoding="utf8") as f_in:
                lines = f_in.readlines()
        except FileNotFoundError:
            pass



Pytest code:

Code: Alles auswählen

import pytest
from file_handler import Filehandler


def test_file_handler_0():
    with pytest.raises(FileNotFoundError):
        Filehandler.read_file("invalid_file.x")



Die Ausgabe ist dann :

plugins: html-2.0.1, metadata-1.8.0
collected 1 item

test_file_handler.py F [100%]

============================================================================================== FAILURES ===============================================================================================
___________________________________________________________________________________________ test_file_handler_0 ____________________________________________________________________________________________

def test_file_handler_0():
with pytest.raises(FileNotFoundError):
> Filehandler.read_file("invalid_file.x")
E Failed: DID NOT RAISE <class 'FileNotFoundError'>

test_file_handler.py
:19: Failed
---------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------
------------------------------------------------------------------ generated html file: file://C:\py\report_test_file_handler.html ------------------------------------------------------------------
========================================================================================== 1 failed in 0.06s ==========================================================================================
Sirius3
User
Beiträge: 18225
Registriert: Sonntag 21. Oktober 2012, 17:20

`read_file` fängt die Exception ja ab, und ignoriert sie, die kann also pytest gar nicht erreichen.
Zur Klasse, das ist keine, erstens, weil sie nur aus einer Funktion besteht und keinen Zustand hat, zweitens, weil die eine Methode kein `self` enthält und weil Du drittens gar keine Instanz erzeugst, sondern die "Methode" direkt aufrufst. `lines` wird mit einem Wert initialisiert, der im Normalfall ignoriert wird, die leere Liste sollte aber nur im Ausnahmefall erzeugt werden (oder gar nicht, wenn die Methode die Exception werfen soll, wie in Deinem Test gefordert).
Datentypen haben in Variablennamen nichts verloren, weder das str in filename_str, noch das f in f_in.
Benutzeravatar
__blackjack__
User
Beiträge: 13931
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`handler` als Namensteil ist auch ein Warnzeichen das man etwas javaesques macht. In wenigen Fällen ist der Namenszusatz gerechtfertigt, hier eher nicht.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
HeinzBacker
User
Beiträge: 19
Registriert: Dienstag 10. März 2020, 20:20

Sirius3 hat geschrieben: Dienstag 10. März 2020, 20:56 `read_file` fängt die Exception ja ab, und ignoriert sie, die kann also pytest gar nicht erreichen.
Zur Klasse, das ist keine, erstens, weil sie nur aus einer Funktion besteht und keinen Zustand hat, zweitens, weil die eine Methode kein `self` enthält und weil Du drittens gar keine Instanz erzeugst, sondern die "Methode" direkt aufrufst. `lines` wird mit einem Wert initialisiert, der im Normalfall ignoriert wird, die leere Liste sollte aber nur im Ausnahmefall erzeugt werden (oder gar nicht, wenn die Methode die Exception werfen soll, wie in Deinem Test gefordert).
Datentypen haben in Variablennamen nichts verloren, weder das str in filename_str, noch das f in f_in.
warum gibts dann Pytest wenn man sowas nicht testen kann. Oder wie soll man das sonst testen?

Wegen der Klasse: ja, du hast da recht. Soll hier nur auf das Wesentliche heruntergebrochen sein.

Datentypen: jeder, der den code im Nodepad anguckt soll auch verstehen, um welchen Datentyp es sich handelt. Daher das Postfix überall. Ich finds besser.
Benutzeravatar
sparrow
User
Beiträge: 4510
Registriert: Freitag 17. April 2009, 10:28

Man braucht keine Namenszusätze, wenn man seinen Variablen vernünftige Namen gibt. 'f_in' kann niemand einordnen, 'file' hingegen schon.
Und was soll denn ein 'filename' anderes sein als eine Zeichenkette?
Da solltest du dich von Dingen lösen, die du möglicherweise von anderen Sprachen kennst.

Wie soll Pytest denn etwas testen, das du absichtlich ignorierst? Wenn du willst, dass ein Fehler gefunden wird, dann darfst du ihn nicht abfangen oder musst ihn mit raise weiterreichen. Aber den Fehler zu fangen und dann einfach nichts zu tun lässt den Fehler logischerweise verschwinden.
HeinzBacker
User
Beiträge: 19
Registriert: Dienstag 10. März 2020, 20:20

sparrow hat geschrieben: Dienstag 10. März 2020, 22:25

Wie soll Pytest denn etwas testen, das du absichtlich ignorierst? Wenn du willst, dass ein Fehler gefunden wird, dann darfst du ihn nicht abfangen oder musst ihn mit raise weiterreichen. Aber den Fehler zu fangen und dann einfach nichts zu tun lässt den Fehler logischerweise verschwinden.
achso, das

Code: Alles auswählen

except FileNotFoundError
verhält sich also wie ein else-Pfad in den gesprungen wird.
Darin sollte man dann etwas unternehmen... (eine Fehlerausgabe mit print?).
ich dachte es gäbe im System noch sowas wie einen Interrupt auf eine Exception-Hook, die der Pytest dann registrieren kann - also davon Notiz bekommt.

Danke
Benutzeravatar
sparrow
User
Beiträge: 4510
Registriert: Freitag 17. April 2009, 10:28

Das offizielle Tutorial hat einen Abschnitt zu Exceptions.

Wenn du eine Ausnahme fängst, musst du sie so abarbeiten, dass das Programm hinterher stabil bzw. kontrolliert weiter läuft. Wenn du das nicht tust oder kannst (weil der Programmfluss es nicht zulässt) dann kannst du dir das fangen der Exception auch sparen. Dann tritt die Aufnahme auf, wird nach oben gereicht und das Programm bricht ab.
Benutzeravatar
__blackjack__
User
Beiträge: 13931
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@HeinzBacker: Wenn Du keine Ahnung hast was Du in der Ausnahmebehandlung eigentlich machen willst, dann lass doch um Himmels willen die Ausnahmebehandlung einfach bleiben. Denn eine `print()`-Ausgabe ist hier sicher keine sinnvolle “Behandlung“, denn wie soll der Aufrufer denn dann wissen das da etwas nicht geklappt hat und darauf reagieren?

`str` ist ein sehr komischer Namenszusatz für ein `bytes`-Objekt. Oder ein `bytearray`-Objekt. Oder ein `pathlib.Path`-Objekt. Oder ein `os.PathLike`-Objekt. Oder irgendein anderes Objekt mit einer `__fspath__()`-Methode. Grunddatentypen in Namen sind oder werden halt sehr schnell *falsch* und damit irreführend. Wenn Du „duck typing“ nicht magst, nimm halt kein Python…
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Sirius3
User
Beiträge: 18225
Registriert: Sonntag 21. Oktober 2012, 17:20

HeinzBacker hat geschrieben: Dienstag 10. März 2020, 21:49 warum gibts dann Pytest wenn man sowas nicht testen kann. Oder wie soll man das sonst testen?
Testen muß man ja nur das, was der Anwender auch zu Gesicht bekommt, Du „behandelst“ aber den Fehler, und der Nutzer bekommt nichts mehr davon mit, also kann und muß man das auch nicht testen.
HeinzBacker hat geschrieben: Dienstag 10. März 2020, 21:49Datentypen: jeder, der den code im Nodepad anguckt soll auch verstehen, um welchen Datentyp es sich handelt. Daher das Postfix überall. Ich finds besser.
Vom Datentyp allein kann ein Nutzer nicht wissen, was gemeint ist. Wenn `filename` nicht ausreicht, um den richtigen Inhalt an die Funktion zu übergeben, dann braucht es bessere Variablennamen oder bessere Dokumentation. Wenn man sich zu sehr auf Datentypen konzentriert, dann kann man kein Verständnis für das Programm entwickeln.
Antworten