doctest — Test interaktiver Python-Beispiele¶
Quellcode: Lib/doctest.py
Das Modul doctest sucht nach Textteilen, die wie interaktive Python-Sitzungen aussehen, und führt diese Sitzungen dann aus, um zu überprüfen, ob sie genau wie gezeigt funktionieren. Es gibt mehrere gängige Möglichkeiten, doctest zu verwenden:
Um zu überprüfen, ob die Docstrings eines Moduls auf dem neuesten Stand sind, indem verifiziert wird, dass alle interaktiven Beispiele noch wie dokumentiert funktionieren.
Um Regressionstests durchzuführen, indem verifiziert wird, dass interaktive Beispiele aus einer Testdatei oder einem Testobjekt wie erwartet funktionieren.
Um Tutorial-Dokumentation für ein Paket zu schreiben, reichlich illustriert mit Eingabe-Ausgabe-Beispielen. Je nachdem, ob die Beispiele oder der erläuternde Text betont werden, hat dies den Charakter von „Literate Testing“ oder „ausführbarer Dokumentation“.
Hier ist ein vollständiges, aber kleines Beispielmodul
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
Wenn Sie example.py direkt von der Befehlszeile aus ausführen, entfaltet doctest seine Magie.
$ python example.py
$
Es gibt keine Ausgabe! Das ist normal und bedeutet, dass alle Beispiele funktioniert haben. Übergeben Sie -v an das Skript, und doctest gibt eine detaillierte Protokollierung dessen aus, was es versucht, und am Ende eine Zusammenfassung aus.
$ python example.py -v
Trying:
factorial(5)
Expecting:
120
ok
Trying:
[factorial(n) for n in range(6)]
Expecting:
[1, 1, 2, 6, 24, 120]
ok
Und so weiter, bis schließlich
Trying:
factorial(1e100)
Expecting:
Traceback (most recent call last):
...
OverflowError: n too large
ok
2 items passed all tests:
1 test in __main__
6 tests in __main__.factorial
7 tests in 2 items.
7 passed.
Test passed.
$
Das ist alles, was Sie wissen müssen, um doctest produktiv nutzen zu können! Legen Sie los. Die folgenden Abschnitte bieten vollständige Details. Beachten Sie, dass es viele Beispiele für Doctests in der Standard-Python-Testsuite und den Bibliotheken gibt. Besonders nützliche Beispiele finden sich in der Standard-Testdatei Lib/test/test_doctest/test_doctest.py.
Hinzugefügt in Version 3.13: Die Ausgabe wird standardmäßig farblich hervorgehoben und kann über Umgebungsvariablen gesteuert werden.
Einfache Verwendung: Überprüfung von Beispielen in Docstrings¶
Der einfachste Weg, mit doctest zu beginnen (aber nicht unbedingt der Weg, den Sie beibehalten werden), ist, jedes Modul M wie folgt zu beenden:
if __name__ == "__main__":
import doctest
doctest.testmod()
Dann untersucht doctest die Docstrings im Modul M.
Das Ausführen des Moduls als Skript bewirkt, dass die Beispiele in den Docstrings ausgeführt und überprüft werden.
python M.py
Dies zeigt nichts an, es sei denn, ein Beispiel schlägt fehl. In diesem Fall werden die fehlgeschlagenen Beispiele und die Ursachen der Fehler an stdout ausgegeben, und die letzte Zeile der Ausgabe lautet ***Test Fehlgeschlagen*** N Fehler., wobei N die Anzahl der fehlgeschlagenen Beispiele ist.
Führen Sie es stattdessen mit dem Schalter -v aus:
python M.py -v
und ein detaillierter Bericht über alle versuchten Beispiele wird auf Standardausgabe ausgegeben, zusammen mit verschiedenen Zusammenfassungen am Ende.
Sie können den ausführlichen Modus erzwingen, indem Sie verbose=True an testmod() übergeben oder ihn verbieten, indem Sie verbose=False übergeben. In beiden Fällen wird sys.argv von testmod() nicht geprüft (daher hat die Angabe von -v oder nicht keine Auswirkung).
Es gibt auch eine Verknüpfung in der Befehlszeile zum Ausführen von testmod(), siehe Abschnitt Befehlszeilenverwendung.
Weitere Informationen zu testmod() finden Sie in Abschnitt Grundlegende API.
Einfache Verwendung: Überprüfung von Beispielen in einer Textdatei¶
Eine weitere einfache Anwendung von doctest ist das Testen interaktiver Beispiele in einer Textdatei. Dies kann mit der Funktion testfile() erfolgen.
import doctest
doctest.testfile("example.txt")
Dieses kurze Skript führt alle interaktiven Python-Beispiele in der Datei example.txt aus und überprüft sie. Der Dateiinhalt wird behandelt, als wäre er ein einziger riesiger Docstring; die Datei muss kein Python-Programm enthalten! Zum Beispiel enthält example.txt möglicherweise Folgendes:
The ``example`` module
======================
Using ``factorial``
-------------------
This is an example text file in reStructuredText format. First import
``factorial`` from the ``example`` module:
>>> from example import factorial
Now use it:
>>> factorial(6)
120
Wenn Sie doctest.testfile("example.txt") ausführen, wird der Fehler in dieser Dokumentation gefunden.
File "./example.txt", line 14, in example.txt
Failed example:
factorial(6)
Expected:
120
Got:
720
Wie bei testmod() zeigt testfile() standardmäßig nichts an, es sei denn, ein Beispiel schlägt fehl. Wenn ein Beispiel fehlschlägt, werden die fehlgeschlagenen Beispiele und die Ursachen der Fehler an stdout ausgegeben, wobei das gleiche Format wie bei testmod() verwendet wird.
Standardmäßig sucht testfile() nach Dateien im Verzeichnis des aufrufenden Moduls. Siehe Abschnitt Grundlegende API für eine Beschreibung der optionalen Argumente, mit denen angegeben werden kann, dass in anderen Speicherorten gesucht werden soll.
Wie testmod() kann die Ausführlichkeit von testfile() mit dem Befehlszeilenschalter -v oder mit dem optionalen Schlüsselwortargument verbose eingestellt werden.
Es gibt auch eine Verknüpfung in der Befehlszeile zum Ausführen von testfile(), siehe Abschnitt Befehlszeilenverwendung.
Weitere Informationen zu testfile() finden Sie in Abschnitt Grundlegende API.
Befehlszeilenverwendung¶
Das Modul doctest kann als Skript von der Befehlszeile aufgerufen werden.
python -m doctest [-v] [-o OPTION] [-f] file [file ...]
- -v, --verbose¶
Ein detaillierter Bericht über alle versuchten Beispiele wird auf Standardausgabe ausgegeben, zusammen mit verschiedenen Zusammenfassungen am Ende.
python -m doctest -v example.py
Dies importiert
example.pyals eigenständiges Modul und führttestmod()darauf aus. Beachten Sie, dass dies möglicherweise nicht korrekt funktioniert, wenn die Datei Teil eines Pakets ist und andere Untermodule aus diesem Paket importiert.Wenn der Dateiname nicht mit
.pyendet, schließtdoctest, dass er stattdessen mittestfile()ausgeführt werden muss.python -m doctest -v example.txt
- -o, --option <option>¶
Option-Flags steuern verschiedene Aspekte des Verhaltens von doctest. Siehe Abschnitt Optionen-Flags.
Hinzugefügt in Version 3.4.
- -f, --fail-fast¶
Dies ist eine Kurzform für
-o FAIL_FAST.Hinzugefügt in Version 3.4.
Wie es funktioniert¶
Dieser Abschnitt untersucht im Detail, wie doctest funktioniert: Welche Docstrings es betrachtet, wie es interaktive Beispiele findet, welchen Ausführungskontext es verwendet, wie es Ausnahmen behandelt und wie Optionen-Flags verwendet werden können, um sein Verhalten zu steuern. Dies sind die Informationen, die Sie benötigen, um Doctest-Beispiele zu schreiben; Informationen zum tatsächlichen Ausführen von Doctest für diese Beispiele finden Sie in den folgenden Abschnitten.
Welche Docstrings werden untersucht?¶
Der Modul-Docstring sowie alle Funktions-, Klassen- und Methoden-Docstrings werden durchsucht. Importierte Objekte im Modul werden nicht durchsucht.
Darüber hinaus gibt es Fälle, in denen Tests Teil eines Moduls sein sollen, aber nicht Teil der Hilfe-Texte sind, was erfordert, dass die Tests nicht im Docstring enthalten sind. Doctest sucht nach einer Modul-weit gültigen Variablen namens __test__ und verwendet diese, um andere Tests zu lokalisieren. Wenn M.__test__ existiert, muss es ein Dict sein, und jeder Eintrag ordnet einen (Zeichenketten-)Namen einem Funktions-, Klassen- oder Zeichenkettenobjekt zu. Aus M.__test__ gefundene Funktions- und Klassenobjekt-Docstrings werden durchsucht, und Zeichenketten werden behandelt, als wären sie Docstrings. In der Ausgabe erscheint ein Schlüssel K in M.__test__ mit dem Namen M.__test__.K.
Platzieren Sie beispielsweise diesen Codeblock am Anfang von example.py:
__test__ = {
'numbers': """
>>> factorial(6)
720
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
}
Der Wert von example.__test__["numbers"] wird als Docstring behandelt und alle darin enthaltenen Tests werden ausgeführt. Es ist wichtig zu beachten, dass der Wert einer Funktion, einem Klassenobjekt oder einem Modul zugeordnet sein kann; wenn ja, durchsucht doctest diese rekursiv nach Docstrings, die dann nach Tests durchsucht werden.
Alle gefundenen Klassen werden auf ähnliche Weise rekursiv durchsucht, um Docstrings in ihren enthaltenen Methoden und verschachtelten Klassen zu testen.
Hinweis
doctest kann nur Klassen und Funktionen automatisch entdecken, die auf Modulebene oder innerhalb anderer Klassen definiert sind.
Da verschachtelte Klassen und Funktionen nur existieren, wenn eine äußere Funktion aufgerufen wird, können sie nicht entdeckt werden. Definieren Sie sie extern, um sie sichtbar zu machen.
Wie werden Docstring-Beispiele erkannt?¶
In den meisten Fällen funktioniert eine Kopie einer interaktiven Konsolensitzung gut, aber doctest versucht keine exakte Emulation einer bestimmten Python-Shell.
>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
... print("yes")
... else:
... print("no")
... print("NO")
... print("NO!!!")
...
no
NO
NO!!!
>>>
Jegliche erwartete Ausgabe muss unmittelbar auf der letzten Zeile mit '>>> ' oder '... ', die den Code enthält, folgen, und die erwartete Ausgabe (falls vorhanden) erstreckt sich bis zur nächsten Zeile mit '>>> ' oder einer Zeile mit nur Leerzeichen.
Das Kleingedruckte
Erwartete Ausgabe darf keine Zeile mit nur Leerzeichen enthalten, da eine solche Zeile das Ende der erwarteten Ausgabe signalisiert. Wenn die erwartete Ausgabe eine Leerzeile enthält, verwenden Sie
<BLANKLINE>in Ihrem Doctest-Beispiel für jede Stelle, an der eine Leerzeile erwartet wird.Alle harten Tabulatorzeichen werden zu Leerzeichen erweitert, wobei Tabstopps bei 8 Spalten verwendet werden. Tabs in der von der getesteten Code erzeugten Ausgabe werden nicht modifiziert. Da alle harten Tabs in der Beispielausgabe erweitert *werden*, bedeutet dies, dass die Doctest nur dann erfolgreich sein kann, wenn die Option
NORMALIZE_WHITESPACEoder eine Direktive aktiv ist. Alternativ kann der Test umgeschrieben werden, um die Ausgabe zu erfassen und sie mit einem erwarteten Wert als Teil des Tests zu vergleichen. Diese Handhabung von Tabs im Quellcode wurde durch Versuch und Irrtum erzielt und hat sich als die am wenigsten fehleranfällige Methode erwiesen. Es ist möglich, einen anderen Algorithmus zur Handhabung von Tabs zu verwenden, indem eine benutzerdefinierte KlasseDocTestParsergeschrieben wird.Ausgabe an stdout wird erfasst, aber nicht an stderr (Ausnahmetracebacks werden auf andere Weise erfasst).
Wenn Sie eine Zeile per Backslash in einer interaktiven Sitzung fortsetzen oder aus einem anderen Grund einen Backslash verwenden, sollten Sie einen Raw-Docstring verwenden, der Ihre Backslashes genau so beibehält, wie Sie sie eingeben.
>>> def f(x): ... r'''Backslashes in a raw docstring: m\n''' ... >>> print(f.__doc__) Backslashes in a raw docstring: m\n
Andernfalls wird der Backslash als Teil der Zeichenkette interpretiert. Zum Beispiel würde der
\noben als neue Zeile interpretiert werden. Alternativ können Sie jeden Backslash in der Doctest-Version verdoppeln (und keinen Raw-String verwenden).>>> def f(x): ... '''Backslashes in a raw docstring: m\\n''' ... >>> print(f.__doc__) Backslashes in a raw docstring: m\n
Die Startspalte spielt keine Rolle.
>>> assert "Easy!" >>> import math >>> math.floor(1.9) 1
und so viele führende Leerzeichen werden von der erwarteten Ausgabe gestrippt, wie in der ursprünglichen
'>>> '-Zeile, die das Beispiel gestartet hat, vorhanden waren.
Was ist der Ausführungskontext?¶
Standardmäßig verwendet doctest bei jedem Auffinden eines zu testenden Docstrings eine *flache Kopie* der Globale von M, sodass das Ausführen von Tests nicht die echten Globale des Moduls verändert und sodass ein Test in M keine Krümel hinterlassen kann, die versehentlich einen anderen Test ermöglichen. Das bedeutet, dass Beispiele beliebige Namen verwenden können, die auf Top-Level in M definiert sind, sowie Namen, die früher im Docstring, der gerade ausgeführt wird, definiert wurden. Beispiele können keine Namen sehen, die in anderen Docstrings definiert sind.
Sie können die Verwendung Ihres eigenen Dictionaries als Ausführungskontext erzwingen, indem Sie stattdessen globs=your_dict an testmod() oder testfile() übergeben.
Was ist mit Ausnahmen?¶
Kein Problem, vorausgesetzt, der Traceback ist die einzige Ausgabe des Beispiels: Fügen Sie einfach den Traceback ein. [1] Da Tracebacks Details enthalten, die sich wahrscheinlich schnell ändern (z. B. genaue Dateipfade und Zeilennummern), ist dies ein Fall, in dem doctest hart daran arbeitet, flexibel zu sein, was es akzeptiert.
Einfaches Beispiel
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
Dieser Doctest ist erfolgreich, wenn ValueError ausgelöst wird, mit dem Detail list.remove(x): x nicht in list wie gezeigt.
Die erwartete Ausgabe für eine Ausnahme muss mit einer Traceback-Kopfzeile beginnen, die eine der folgenden beiden Zeilen sein kann, gleichmäßig eingerückt wie die erste Zeile des Beispiels:
Traceback (most recent call last):
Traceback (innermost last):
Auf die Traceback-Kopfzeile folgt ein optionaler Traceback-Stack, dessen Inhalt von doctest ignoriert wird. Der Traceback-Stack wird typischerweise weggelassen oder wörtlich aus einer interaktiven Sitzung kopiert.
Der Traceback-Stack wird gefolgt von dem interessantesten Teil: den Zeilen, die den Ausnahmetyp und das Detail enthalten. Dies ist normalerweise die letzte Zeile eines Tracebacks, kann aber über mehrere Zeilen gehen, wenn die Ausnahme ein mehrzeiliges Detail hat.
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: multi
line
detail
Die letzten drei Zeilen (beginnend mit ValueError) werden mit dem Typ und Detail der Ausnahme verglichen, der Rest wird ignoriert.
Am besten ist es, den Traceback-Stack wegzulassen, es sei denn, er fügt dem Beispiel einen erheblichen Dokumentationswert hinzu. Daher ist das letzte Beispiel wahrscheinlich besser:
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
...
ValueError: multi
line
detail
Beachten Sie, dass Tracebacks sehr speziell behandelt werden. Insbesondere im umgeschriebenen Beispiel ist die Verwendung von ... unabhängig von der ELLIPSIS-Option von doctest. Der Punkt in diesem Beispiel könnte weggelassen werden oder es könnten genauso gut drei (oder dreihundert) Kommas oder Ziffern sein, oder eine eingerückte Mitschrift eines Monty Python-Sketches.
Einige Details, die Sie einmal lesen sollten, aber nicht auswendig lernen müssen.
Doctest kann nicht erraten, ob Ihre erwartete Ausgabe von einem Ausnahme-Traceback oder von normalem Drucken stammt. Zum Beispiel besteht ein Beispiel, das
ValueError: 42 ist primerwartet, obValueErrortatsächlich ausgelöst wird oder ob das Beispiel nur diesen Traceback-Text ausgibt. In der Praxis beginnt die normale Ausgabe selten mit einer Traceback-Kopfzeile, daher schafft dies keine wirklichen Probleme.Jede Zeile des Traceback-Stacks (falls vorhanden) muss weiter eingerückt sein als die erste Zeile des Beispiels *oder* mit einem nicht-alphanumerischen Zeichen beginnen. Die erste Zeile nach der Traceback-Kopfzeile, die gleichmäßig eingerückt ist und mit einem alphanumerischen Zeichen beginnt, wird als Beginn des Ausnahmedetails betrachtet. Natürlich macht dies das Richtige für echte Tracebacks.
Wenn die doctest-Option
IGNORE_EXCEPTION_DETAILangegeben ist, wird alles nach dem am weitesten links stehenden Doppelpunkt und allen Modulinformationen im Ausnahmenamen ignoriert.Die interaktive Shell lässt die Traceback-Kopfzeile für einige
SyntaxErrors weg. Aber doctest verwendet die Traceback-Kopfzeile, um Ausnahmen von Nicht-Ausnahmen zu unterscheiden. In dem seltenen Fall, in dem Sie einenSyntaxErrortesten müssen, der die Traceback-Kopfzeile weglässt, müssen Sie die Traceback-Kopfzeile manuell zu Ihrem Testbeispiel hinzufügen.
Für einige Ausnahmen zeigt Python die Position des Fehlers mit
^-Markierungen und Tilden an.>>> 1 + None File "<stdin>", line 1 1 + None ~~^~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
Da die Zeilen, die die Position des Fehlers anzeigen, vor dem Ausnahmetyp und -detail stehen, werden sie von doctest nicht geprüft. Beispielsweise würde der folgende Test bestehen, obwohl er die
^-Markierung an der falschen Stelle platziert.>>> 1 + None File "<stdin>", line 1 1 + None ^~~~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
Optionen-Flags¶
Eine Reihe von Optionen-Flags steuern verschiedene Aspekte des Verhaltens von doctest. Symbolische Namen für die Flags werden als Modulkonstanten bereitgestellt, die per bitweisem OR (bitwise OR) verknüpft und an verschiedene Funktionen übergeben werden können. Die Namen können auch in doctest-Direktiven verwendet und über die Befehlszeilenschnittstelle von doctest über die Option -o übergeben werden.
Die erste Gruppe von Optionen definiert Semantik für Tests und steuert Aspekte, wie doctest entscheidet, ob die tatsächliche Ausgabe mit der erwarteten Ausgabe eines Beispiels übereinstimmt.
- doctest.DONT_ACCEPT_TRUE_FOR_1¶
Standardmäßig gilt: Wenn ein Block mit erwarteter Ausgabe nur
1enthält, wird ein Block mit tatsächlicher Ausgabe, der nur1oder nurTrueenthält, als übereinstimmend betrachtet, und ähnlich für0gegenüberFalse. WennDONT_ACCEPT_TRUE_FOR_1angegeben ist, sind beide Substitutionen nicht erlaubt. Das Standardverhalten berücksichtigt, dass Python den Rückgabetyp vieler Funktionen von Integer auf Boolean geändert hat; Doctests, die „kleine Integer“-Ausgaben erwarten, funktionieren in diesen Fällen weiterhin. Diese Option wird wahrscheinlich verschwinden, aber nicht für mehrere Jahre.
- doctest.DONT_ACCEPT_BLANKLINE¶
Standardmäßig gilt: Wenn ein Block mit erwarteter Ausgabe eine Zeile enthält, die nur die Zeichenkette
<BLANKLINE>enthält, dann passt diese Zeile zu einer Leerzeile in der tatsächlichen Ausgabe. Da eine echte Leerzeile die erwartete Ausgabe abgrenzt, ist dies die einzige Möglichkeit, eine erwartete Leerzeile zu kommunizieren. WennDONT_ACCEPT_BLANKLINEangegeben ist, ist diese Substitution nicht erlaubt.
- doctest.NORMALIZE_WHITESPACE¶
Wenn angegeben, werden alle Leerzeichenfolgen (Leerzeichen und Zeilenumbrüche) als gleich behandelt. Jede Leerzeichenfolge in der erwarteten Ausgabe passt zu jeder Leerzeichenfolge in der tatsächlichen Ausgabe. Standardmäßig müssen Leerzeichen exakt übereinstimmen.
NORMALIZE_WHITESPACEist besonders nützlich, wenn eine Zeile erwarteter Ausgabe sehr lang ist und Sie sie in Ihrem Quellcode über mehrere Zeilen umbrechen möchten.
- doctest.ELLIPSIS¶
Wenn angegeben, kann ein Ellipsismarker (
...) in der erwarteten Ausgabe mit einer beliebigen Teilzeichenkette in der tatsächlichen Ausgabe übereinstimmen. Dies schließt Teilzeichenketten ein, die sich über Zeilen erstrecken, und leere Teilzeichenketten, daher ist es am besten, die Verwendung davon einfach zu halten. Komplizierte Verwendungen können zu denselben Überraschungen des Typs „Ups, es hat zu viel gepasst!“ führen, denen.*in regulären Ausdrücken anfällig ist.
- doctest.IGNORE_EXCEPTION_DETAIL¶
Wenn angegeben, bestehen Doctests, die Ausnahmen erwarten, so lange, wie eine Ausnahme vom erwarteten Typ ausgelöst wird, auch wenn die Details (Meldung und vollqualifizierter Ausnahmetyp) nicht übereinstimmen.
Beispielsweise besteht ein Beispiel, das
ValueError: 42erwartet, wenn die tatsächliche ausgelöste AusnahmeValueError: 3*14ist, schlägt aber fehl, wenn beispielsweise einTypeErrorstattdessen ausgelöst wird. Außerdem werden alle vollqualifizierten Namen ignoriert, die vor der Ausnahmeklasse aufgeführt sind und zwischen Implementierungen und Versionen von Python sowie den verwendeten Code/Bibliotheken variieren können. Daher funktionieren alle drei dieser Variationen mit dem angegebenen Flag:>>> raise Exception('message') Traceback (most recent call last): Exception: message >>> raise Exception('message') Traceback (most recent call last): builtins.Exception: message >>> raise Exception('message') Traceback (most recent call last): __main__.Exception: message
Beachten Sie, dass
ELLIPSISauch verwendet werden kann, um die Details der Ausnahmemeldung zu ignorieren, aber ein solcher Test kann immer noch fehlschlagen, je nachdem, ob der Modulname vorhanden ist oder exakt übereinstimmt.Geändert in Version 3.2:
IGNORE_EXCEPTION_DETAILignoriert jetzt auch Informationen, die sich auf das Modul beziehen, das die zu testende Ausnahme enthält.
- doctest.SKIP¶
Wenn angegeben, wird das Beispiel überhaupt nicht ausgeführt. Dies kann in Kontexten nützlich sein, in denen doctest-Beispiele sowohl als Dokumentation als auch als Testfälle dienen und ein Beispiel zu Dokumentationszwecken enthalten sein soll, aber nicht überprüft werden soll. Z.B. könnte die Ausgabe des Beispiels zufällig sein; oder das Beispiel könnte von Ressourcen abhängen, die dem Testtreiber nicht zur Verfügung stünden.
Das SKIP-Flag kann auch zum temporären „Auskommentieren“ von Beispielen verwendet werden.
- doctest.COMPARISON_FLAGS¶
Eine Bitmaske, die alle oben genannten Vergleichsflags per OR verknüpft.
Die zweite Gruppe von Optionen steuert, wie Testfehler gemeldet werden.
- doctest.REPORT_UDIFF¶
Wenn angegeben, werden Fehler, die mehrzeilige erwartete und tatsächliche Ausgaben beinhalten, in einem einheitlichen Diff angezeigt.
- doctest.REPORT_CDIFF¶
Wenn angegeben, werden Fehler, die mehrzeilige erwartete und tatsächliche Ausgaben beinhalten, in einem Kontext-Diff angezeigt.
- doctest.REPORT_NDIFF¶
Wenn angegeben, werden Unterschiede mit
difflib.Differberechnet, wobei derselbe Algorithmus wie das beliebte Dienstprogrammndiff.pyverwendet wird. Dies ist die einzige Methode, die Unterschiede innerhalb von Zeilen sowie über Zeilen hinweg markiert. Wenn beispielsweise eine Zeile erwarteter Ausgabe die Ziffer1enthält, wo die tatsächliche Ausgabe den Buchstabenlenthält, wird eine Zeile mit einem Caret eingefügt, das die abweichenden Spaltenpositionen markiert.
- doctest.REPORT_ONLY_FIRST_FAILURE¶
Wenn angegeben, wird das erste fehlschlagende Beispiel in jedem Doctest angezeigt, aber die Ausgabe für alle verbleibenden Beispiele wird unterdrückt. Dies verhindert, dass doctest korrekte Beispiele meldet, die aufgrund früherer Fehler fehlschlagen; es kann aber auch fehlerhafte Beispiele verbergen, die unabhängig vom ersten Fehler fehlschlagen. Wenn
REPORT_ONLY_FIRST_FAILUREangegeben ist, werden die verbleibenden Beispiele immer noch ausgeführt und zählen zur Gesamtzahl der gemeldeten Fehler; nur die Ausgabe wird unterdrückt.
- doctest.FAIL_FAST¶
Wenn angegeben, wird nach dem ersten fehlschlagenden Beispiel beendet und nicht versucht, die verbleibenden Beispiele auszuführen. Somit wird die Anzahl der gemeldeten Fehler höchstens 1 betragen. Dieses Flag kann beim Debuggen nützlich sein, da Beispiele nach dem ersten Fehler nicht einmal Debugging-Ausgaben erzeugen.
- doctest.REPORTING_FLAGS¶
Eine Bitmaske, die alle oben genannten Reporting-Flags per OR verknüpft.
Es gibt auch eine Möglichkeit, neue Optionsflag-Namen zu registrieren. Dies ist jedoch nur nützlich, wenn Sie beabsichtigen, die Interna von doctest durch Unterklassenbildung zu erweitern.
- doctest.register_optionflag(name)¶
Erzeugt ein neues Optionsflag mit dem gegebenen Namen und gibt dessen ganzzahligen Wert zurück.
register_optionflag()kann beim Unterklassen bilden vonOutputCheckeroderDocTestRunnerverwendet werden, um neue Optionen zu erstellen, die von Ihren Unterklassen unterstützt werden.register_optionflag()sollte immer mit dem folgenden Idiom aufgerufen werden.MY_FLAG = register_optionflag('MY_FLAG')
Direktiven¶
Doctest-Direktiven können verwendet werden, um die Optionsflags für ein einzelnes Beispiel zu ändern. Doctest-Direktiven sind spezielle Python-Kommentare, die dem Quellcode eines Beispiels folgen.
directive: "#" "doctest:"directive_optionsdirective_options:directive_option(","directive_option)* directive_option:on_or_offdirective_option_nameon_or_off: "+" | "-" directive_option_name: "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...
Leerzeichen sind zwischen dem + oder - und dem Namen der Direktive nicht erlaubt. Der Name der Direktive kann jeder der oben erklärten Optionsflag-Namen sein.
Doctest-Direktiven eines Beispiels ändern das Verhalten von Doctest für dieses einzelne Beispiel. Verwenden Sie +, um das benannte Verhalten zu aktivieren, oder -, um es zu deaktivieren.
Zum Beispiel besteht dieser Test
>>> print(list(range(20))) # doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Ohne die Direktive würde er fehlschlagen, sowohl weil die tatsächliche Ausgabe keine zwei Leerzeichen vor den einstelligen Listenlementen hat, als auch weil die tatsächliche Ausgabe auf einer einzigen Zeile erfolgt. Dieser Test besteht ebenfalls und erfordert dafür ebenfalls eine Direktive.
>>> print(list(range(20))) # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]
Mehrere Direktiven können auf einer einzelnen physikalischen Zeile durch Kommas getrennt verwendet werden.
>>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
Wenn mehrere Direktivenkommentare für ein einzelnes Beispiel verwendet werden, werden sie kombiniert.
>>> print(list(range(20))) # doctest: +ELLIPSIS
... # doctest: +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
Wie das vorherige Beispiel zeigt, können Sie Ihrem Beispiel ...-Zeilen hinzufügen, die nur Direktiven enthalten. Dies kann nützlich sein, wenn ein Beispiel zu lang ist, als dass eine Direktive bequem auf derselben Zeile Platz hätte.
>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]
Beachten Sie, dass, da alle Optionen standardmäßig deaktiviert sind und Direktiven nur für das Beispiel gelten, in dem sie erscheinen, das Aktivieren von Optionen (über + in einer Direktive) normalerweise die einzig sinnvolle Wahl ist. Optionsflags können jedoch auch an Funktionen übergeben werden, die Doctests ausführen, und legen andere Standardwerte fest. In solchen Fällen kann das Deaktivieren einer Option über - in einer Direktive nützlich sein.
Warnungen¶
doctest ist strikt bei der Anforderung exakter Übereinstimmungen der erwarteten Ausgabe. Selbst wenn ein einzelnes Zeichen nicht übereinstimmt, schlägt der Test fehl. Dies wird Sie wahrscheinlich ein paar Mal überraschen, wenn Sie genau lernen, was Python für die Ausgabe garantiert und was nicht. Wenn Sie beispielsweise ein Set drucken, garantiert Python nicht, dass das Element in einer bestimmten Reihenfolge gedruckt wird, daher ist ein Test wie
>>> foo()
{"spam", "eggs"}
anfällig! Eine Umgehungsmöglichkeit ist,
>>> foo() == {"spam", "eggs"}
True
stattdessen. Eine andere ist,
>>> d = sorted(foo())
>>> d
['eggs', 'spam']
Es gibt andere, aber Sie verstehen, was gemeint ist.
Eine weitere schlechte Idee ist, Dinge zu drucken, die eine Objektadresse einbetten, wie zum Beispiel
>>> id(1.0) # certain to fail some of the time
7948648
>>> class C: pass
>>> C() # the default repr() for instances embeds an address
<C object at 0x00AC18F0>
Die Direktive ELLIPSIS bietet einen schönen Ansatz für das letzte Beispiel.
>>> C() # doctest: +ELLIPSIS
<C object at 0x...>
Gleitkommazahlen unterliegen ebenfalls kleinen Ausgabevariationen zwischen Plattformen, da Python bei einigen Gleitkomma-Berechnungen auf die plattformabhängige C-Bibliothek zurückgreift und diese Bibliotheken hier in Bezug auf die Qualität stark variieren.
>>> 1000**0.1 # risky
1.9952623149688797
>>> round(1000**0.1, 9) # safer
1.995262315
>>> print(f'{1000**0.1:.4f}') # much safer
1.9953
Zahlen der Form I/2.**J sind auf allen Plattformen sicher, und ich erfinde oft Doctest-Beispiele, um Zahlen dieser Form zu erzeugen.
>>> 3./4 # utterly safe
0.75
Einfache Brüche sind für Menschen auch leichter verständlich, und das macht eine bessere Dokumentation aus.
Grundlegende API¶
Die Funktionen testmod() und testfile() bieten eine einfache Schnittstelle zu Doctest, die für die meisten grundlegenden Anwendungen ausreichend sein sollte. Für eine informellere Einführung in diese beiden Funktionen siehe die Abschnitte Einfache Verwendung: Überprüfung von Beispielen in Docstrings und Einfache Verwendung: Überprüfung von Beispielen in einer Textdatei.
- doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)¶
Alle Argumente außer filename sind optional und sollten als Schlüsselwortargumente angegeben werden.
Testet Beispiele in der Datei namens filename. Gibt
(failure_count, test_count)zurück.Das optionale Argument module_relative gibt an, wie der Dateiname interpretiert werden soll.
Wenn module_relative
True(Standard) ist, dann gibt filename einen OS-unabhängigen Modul-relativen Pfad an. Standardmäßig ist dieser Pfad relativ zum Verzeichnis des aufrufenden Moduls; wenn jedoch das Argument package angegeben ist, dann ist er relativ zu diesem Paket. Um die OS-Unabhängigkeit zu gewährleisten, sollte filename/-Zeichen zur Trennung von Pfadsegmenten verwenden und darf kein absoluter Pfad sein (d. h. er darf nicht mit/beginnen).Wenn module_relative
Falseist, dann gibt filename einen OS-spezifischen Pfad an. Der Pfad kann absolut oder relativ sein; relative Pfade werden relativ zum aktuellen Arbeitsverzeichnis aufgelöst.
Das optionale Argument name gibt den Namen des Tests an; standardmäßig oder wenn
None, wirdos.path.basename(filename)verwendet.Das optionale Argument package ist ein Python-Paket oder der Name eines Python-Pakets, dessen Verzeichnis als Basisverzeichnis für Modul-relative Dateinamen verwendet werden soll. Wenn kein Paket angegeben ist, wird das Verzeichnis des aufrufenden Moduls als Basisverzeichnis für Modul-relative Dateinamen verwendet. Es ist ein Fehler, package anzugeben, wenn module_relative
Falseist.Das optionale Argument globs gibt ein Dictionary an, das als Globals beim Ausführen von Beispielen verwendet wird. Eine neue flache Kopie dieses Dictionaries wird für das Doctest erstellt, sodass dessen Beispiele mit einer sauberen Weste beginnen. Standardmäßig oder wenn
None, wird ein neues leeres Dictionary verwendet.Das optionale Argument extraglobs gibt ein Dictionary an, das in die zum Ausführen von Beispielen verwendeten Globals zusammengeführt wird. Dies funktioniert ähnlich wie
dict.update(): Wenn globs und extraglobs einen gemeinsamen Schlüssel haben, erscheint der zugehörige Wert in extraglobs im kombinierten Dictionary. Standardmäßig oder wennNone, werden keine zusätzlichen Globals verwendet. Dies ist eine erweiterte Funktion, die die Parametrisierung von Doctests ermöglicht. Zum Beispiel kann ein Doctest für eine Basisklasse geschrieben werden, wobei ein generischer Name für die Klasse verwendet wird, und dann wiederverwendet werden, um eine beliebige Anzahl von Unterklassen zu testen, indem ein extraglobs-Dictionary übergeben wird, das den generischen Namen auf die zu testende Unterklasse abbildet.Das optionale Argument verbose gibt viele Informationen aus, wenn es wahr ist, und nur Fehler, wenn es falsch ist. Standardmäßig oder wenn
None, ist es genau dann wahr, wenn'-v'insys.argventhalten ist.Das optionale Argument report gibt am Ende eine Zusammenfassung aus, wenn es wahr ist, andernfalls wird am Ende nichts ausgegeben. Im ausführlichen Modus ist die Zusammenfassung detailliert, andernfalls ist die Zusammenfassung sehr kurz (tatsächlich leer, wenn alle Tests bestanden wurden).
Das optionale Argument optionflags (Standardwert
0) nimmt das Bitweise OR der Optionsflags. Siehe Abschnitt Optionsflags.Das optionale Argument raise_on_error ist standardmäßig falsch. Wenn es wahr ist, wird bei der ersten fehlgeschlagenen oder unerwarteten Ausnahme in einem Beispiel eine Ausnahme ausgelöst. Dies ermöglicht es, Fehler nach Beendigung zu debuggen. Das Standardverhalten ist, mit dem Ausführen von Beispielen fortzufahren.
Das optionale Argument parser gibt einen
DocTestParser(oder eine Unterklasse) an, der zum Extrahieren von Tests aus den Dateien verwendet werden soll. Er ist standardmäßig ein normaler Parser (d. h.DocTestParser()).Das optionale Argument encoding gibt eine Kodierung an, die zum Konvertieren der Datei in Unicode verwendet werden soll.
- doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)¶
Alle Argumente sind optional, und alle außer m sollten als Schlüsselwortargumente angegeben werden.
Testet Beispiele in Docstrings von Funktionen und Klassen, die von Modul m erreichbar sind (oder Modul
__main__, wenn m nicht angegeben oderNoneist), beginnend mitm.__doc__.Testet auch Beispiele, die von dem Dictionary
m.__test__erreichbar sind, falls es existiert.m.__test__bildet Namen (Strings) auf Funktionen, Klassen und Strings ab; Funktions- und Klassendocstrings werden nach Beispielen durchsucht; Strings werden direkt durchsucht, als wären sie Docstrings.Nur Docstrings, die zu Objekten gehören, die zu Modul m gehören, werden durchsucht.
Gibt
(failure_count, test_count)zurück.Das optionale Argument name gibt den Namen des Moduls an; standardmäßig oder wenn
None, wirdm.__name__verwendet.Das optionale Argument exclude_empty ist standardmäßig falsch. Wenn es wahr ist, werden Objekte, für die keine Doctests gefunden werden, von der Betrachtung ausgeschlossen. Der Standardwert ist ein Rückwärtskompatibilitäts-Hack, damit Code, der
doctest.master.summarizein Verbindung mittestmod()verwendet, weiterhin Ausgaben für Objekte ohne Tests erhält. Das Argument exclude_empty für den neuerenDocTestFinder-Konstruktor ist standardmäßig wahr.Die optionalen Argumente extraglobs, verbose, report, optionflags, raise_on_error und globs sind die gleichen wie für die Funktion
testfile()oben, außer dass globs standardmäßigm.__dict__ist.
- doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)¶
Testet Beispiele, die mit dem Objekt f verknüpft sind; zum Beispiel kann f ein String, ein Modul, eine Funktion oder ein Klassenobjekt sein.
Eine flache Kopie des Dictionary-Arguments globs wird für den Ausführungskontext verwendet.
Das optionale Argument name wird in Fehlermeldungen verwendet und ist standardmäßig
"NoName".Wenn das optionale Argument verbose wahr ist, wird auch dann eine Ausgabe generiert, wenn keine Fehler auftreten. Standardmäßig wird nur bei einem Beispiel-Fehler eine Ausgabe generiert.
Das optionale Argument compileflags gibt die Menge von Flags an, die vom Python-Compiler beim Ausführen der Beispiele verwendet werden sollen. Standardmäßig oder wenn
None, werden Flags abgeleitet, die der Menge von zukünftigen Features entsprechen, die in globs gefunden wurden.Das optionale Argument optionflags funktioniert wie für die Funktion
testfile()oben.
Unittest API¶
Wenn Ihre Sammlung von Doctest-Modulen wächst, benötigen Sie eine Möglichkeit, alle ihre Doctests systematisch auszuführen. doctest bietet zwei Funktionen, die verwendet werden können, um unittest-Testsuiten aus Modulen und Textdateien zu erstellen, die Doctests enthalten. Um die unittest-Testentdeckung zu integrieren, fügen Sie eine load_tests-Funktion in Ihr Testmodul ein.
import unittest
import doctest
import my_module_with_doctests
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
return tests
Es gibt zwei Hauptfunktionen zum Erstellen von unittest.TestSuite-Instanzen aus Textdateien und Modulen mit Doctests.
- doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)¶
Konvertiert Doctest-Tests aus einer oder mehreren Textdateien in eine
unittest.TestSuite.Die zurückgegebene
unittest.TestSuitesoll vom Unittest-Framework ausgeführt werden und testet die interaktiven Beispiele in jeder Datei. Wenn ein Beispiel in einer Datei fehlschlägt, schlägt der synthetisierte Unit-Test fehl und einefailureException-Ausnahme wird ausgelöst, die den Namen der Datei, die den Test enthält, und eine (manchmal ungefähre) Zeilennummer anzeigt. Wenn alle Beispiele in einer Datei übersprungen werden, wird auch der synthetisierte Unit-Test als übersprungen markiert.Geben Sie einen oder mehrere Pfade (als Strings) zu zu prüfenden Textdateien an.
Optionen können als Schlüsselwortargumente angegeben werden.
Das optionale Argument module_relative gibt an, wie die Dateinamen in paths interpretiert werden sollen.
Wenn module_relative
True(Standard) ist, dann gibt jeder Dateiname in paths einen OS-unabhängigen Modul-relativen Pfad an. Standardmäßig ist dieser Pfad relativ zum Verzeichnis des aufrufenden Moduls; wenn jedoch das Argument package angegeben ist, dann ist er relativ zu diesem Paket. Um die OS-Unabhängigkeit zu gewährleisten, sollte jeder Dateiname/-Zeichen zur Trennung von Pfadsegmenten verwenden und darf kein absoluter Pfad sein (d. h. er darf nicht mit/beginnen).Wenn module_relative
Falseist, dann gibt jeder Dateiname in paths einen OS-spezifischen Pfad an. Der Pfad kann absolut oder relativ sein; relative Pfade werden relativ zum aktuellen Arbeitsverzeichnis aufgelöst.
Das optionale Argument package ist ein Python-Paket oder der Name eines Python-Pakets, dessen Verzeichnis als Basisverzeichnis für Modul-relative Dateinamen in paths verwendet werden soll. Wenn kein Paket angegeben ist, wird das Verzeichnis des aufrufenden Moduls als Basisverzeichnis für Modul-relative Dateinamen verwendet. Es ist ein Fehler, package anzugeben, wenn module_relative
Falseist.Das optionale Argument setUp gibt eine Einrichtungsfunktion für die Testsuite an. Diese wird vor dem Ausführen der Tests in jeder Datei aufgerufen. Die setUp-Funktion erhält ein
DocTest-Objekt. Die setUp-Funktion kann auf die Test-Globals als Attributglobsdes übergebenen Tests zugreifen.Das optionale Argument tearDown gibt eine Abbaufunktion für die Testsuite an. Diese wird nach dem Ausführen der Tests in jeder Datei aufgerufen. Die tearDown-Funktion erhält ein
DocTest-Objekt. Die tearDown-Funktion kann auf die Test-Globals als Attributglobsdes übergebenen Tests zugreifen.Das optionale Argument globs ist ein Dictionary, das die anfänglichen globalen Variablen für die Tests enthält. Für jeden Test wird eine neue Kopie dieses Dictionaries erstellt. Standardmäßig ist globs ein neues leeres Dictionary.
Das optionale Argument optionflags gibt die Standard-Doctest-Optionen für die Tests an, die durch bitweises OR von einzelnen Optionsflags gebildet werden. Siehe Abschnitt Optionsflags. Siehe die Funktion
set_unittest_reportflags()unten für eine bessere Möglichkeit, Reporting-Optionen festzulegen.Das optionale Argument parser gibt einen
DocTestParser(oder eine Unterklasse) an, der zum Extrahieren von Tests aus den Dateien verwendet werden soll. Er ist standardmäßig ein normaler Parser (d. h.DocTestParser()).Das optionale Argument encoding gibt eine Kodierung an, die zum Konvertieren der Datei in Unicode verwendet werden soll.
Das globale
__file__wird zu den Globals hinzugefügt, die Doctests bereitgestellt werden, die mitDocFileSuite()aus einer Textdatei geladen werden.
- doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, optionflags=0, checker=None)¶
Konvertiert Doctest-Tests für ein Modul in eine
unittest.TestSuite.Die zurückgegebene
unittest.TestSuitesoll vom Unittest-Framework ausgeführt werden und testet jeden Doctest im Modul. Jede Docstring wird als separater Unit-Test ausgeführt. Wenn einer der Doctests fehlschlägt, schlägt der synthetisierte Unit-Test fehl und eineunittest.TestCase.failureException-Ausnahme wird ausgelöst, die den Namen der Datei, die den Test enthält, und eine (manchmal ungefähre) Zeilennummer anzeigt. Wenn alle Beispiele in einer Docstring übersprungen werden, dann wird derDas optionale Argument module gibt das zu testende Modul an. Es kann ein Modulobjekt oder ein (möglicherweise gepunkteter) Modulname sein. Wenn es nicht angegeben ist, wird das Modul verwendet, das diese Funktion aufruft.
Das optionale Argument globs ist ein Dictionary, das die anfänglichen globalen Variablen für die Tests enthält. Für jeden Test wird eine neue Kopie dieses Dictionaries erstellt. Standardmäßig ist globs das
__dict__des Moduls.Das optionale Argument extraglobs gibt einen zusätzlichen Satz von globalen Variablen an, der in globs zusammengeführt wird. Standardmäßig werden keine zusätzlichen Globals verwendet.
Das optionale Argument test_finder ist das
DocTestFinder-Objekt (oder ein Drop-in-Ersatz), das zum Extrahieren von Doctests aus dem Modul verwendet wird.Die optionalen Argumente setUp, tearDown und optionflags sind die gleichen wie für die Funktion
DocFileSuite()oben, aber sie werden für jede Docstring aufgerufen.Diese Funktion verwendet die gleiche Suchtechnik wie
testmod().Geändert in Version 3.5:
DocTestSuite()gibt eine leereunittest.TestSuitezurück, wenn module keine Docstrings enthält, anstattValueErrorauszulösen.
Intern erstellt DocTestSuite() eine unittest.TestSuite aus doctest.DocTestCase-Instanzen, und DocTestCase ist eine Unterklasse von unittest.TestCase. DocTestCase ist hier nicht dokumentiert (es ist ein internes Detail), aber die Untersuchung seines Codes kann Fragen zur genauen Funktionsweise der unittest-Integration beantworten.
Ebenso erstellt DocFileSuite() eine unittest.TestSuite aus doctest.DocFileCase-Instanzen, und DocFileCase ist eine Unterklasse von DocTestCase.
Beide Wege, eine unittest.TestSuite zu erstellen, führen Instanzen von DocTestCase aus. Dies ist aus einem subtilen Grund wichtig: Wenn Sie doctest-Funktionen selbst ausführen, können Sie die verwendeten doctest-Optionen direkt steuern, indem Sie Options-Flags an doctest-Funktionen übergeben. Wenn Sie jedoch ein unittest-Framework schreiben, kontrolliert unittest letztendlich, wann und wie Tests ausgeführt werden. Der Autor des Frameworks möchte normalerweise die doctest-Berichterstattungsoptionen steuern (vielleicht, z.B., durch Kommandozeilenoptionen angegeben), aber es gibt keine Möglichkeit, Optionen über unittest an doctest-Testläufer zu übergeben.
Aus diesem Grund unterstützt doctest auch die Vorstellung von doctest-Berichterstattungs-Flags, die spezifisch für die Unterstützung von unittest sind, über diese Funktion
- doctest.set_unittest_reportflags(flags)¶
Setzt die zu verwendenden
doctest-Berichterstattungs-Flags.Das Argument flags nimmt das Bit-ODER von Options-Flags. Siehe Abschnitt Option Flags. Es können nur "Reporting Flags" verwendet werden.
Dies ist eine Modul-globale Einstellung und wirkt sich auf alle zukünftigen Doctests aus, die vom Modul
unittestausgeführt werden: Die MethoderunTest()vonDocTestCaseprüft die Options-Flags, die für den Testfall beim Erstellen derDocTestCase-Instanz angegeben wurden. Wenn keine Berichterstattungs-Flags angegeben wurden (was der typische und erwartete Fall ist), werden dieunittest-Berichterstattungs-Flags vondoctestin die Options-Flags bitwise OR-verknüpft, und die so erweiterten Options-Flags werden an dieDocTestRunner-Instanz übergeben, die zum Ausführen des Doctests erstellt wird. Wenn beim Erstellen derDocTestCase-Instanz Berichterstattungs-Flags angegeben wurden, werden dieunittest-Berichterstattungs-Flags vondoctestignoriert.Der Wert der
unittest-Berichterstattungs-Flags, die vor dem Aufruf der Funktion gültig waren, wird von der Funktion zurückgegeben.
Erweitertes API¶
Die Basis-API ist ein einfacher Wrapper, der dazu gedacht ist, die Verwendung von Doctest zu vereinfachen. Er ist ziemlich flexibel und sollte die Bedürfnisse der meisten Benutzer erfüllen; wenn Sie jedoch eine feinere Kontrolle über das Testen benötigen oder die Fähigkeiten von Doctest erweitern möchten, sollten Sie die erweiterte API verwenden.
Die erweiterte API dreht sich um zwei Container-Klassen, die verwendet werden, um die interaktiven Beispiele zu speichern, die aus Doctest-Fällen extrahiert werden.
Example: Eine einzelne Python Anweisung, gepaart mit ihrer erwarteten Ausgabe.DocTest: Eine Sammlung vonExamples, typischerweise aus einem einzelnen Docstring oder einer Textdatei extrahiert.
Zusätzliche Verarbeitungsklassen sind definiert, um Doctest-Beispiele zu finden, zu parsen, auszuführen und zu überprüfen.
DocTestFinder: Findet alle Docstrings in einem gegebenen Modul und verwendet einenDocTestParser, um aus jedem Docstring, der interaktive Beispiele enthält, eineDocTestzu erstellen.DocTestParser: Erstellt einDocTest-Objekt aus einem String (wie z.B. dem Docstring eines Objekts).DocTestRunner: Führt die Beispiele in einerDocTestaus und verwendet einenOutputChecker, um deren Ausgabe zu verifizieren.OutputChecker: Vergleicht die tatsächliche Ausgabe eines Doctest-Beispiels mit der erwarteten Ausgabe und entscheidet, ob sie übereinstimmen.
Die Beziehungen zwischen diesen Verarbeitungsklassen werden im folgenden Diagramm zusammengefasst.
list of:
+------+ +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+ | ^ +---------+ | ^ (printed)
| | | Example | | |
v | | ... | v |
DocTestParser | Example | OutputChecker
+---------+
DocTest-Objekte¶
- class doctest.DocTest(examples, globs, name, filename, lineno, docstring)¶
Eine Sammlung von Doctest-Beispielen, die im selben Namensraum ausgeführt werden sollen. Die Konstruktorargumente werden zur Initialisierung der Attribute mit denselben Namen verwendet.
DocTestdefiniert die folgenden Attribute. Sie werden vom Konstruktor initialisiert und sollten nicht direkt modifiziert werden.- examples¶
Eine Liste von
Example-Objekten, die die einzelnen interaktiven Python-Beispiele kodieren, die von diesem Test ausgeführt werden sollen.
- globs¶
Der Namensraum (auch Globale genannt), in dem die Beispiele ausgeführt werden sollen. Dies ist ein Dictionary, das Namen auf Werte abbildet. Alle Änderungen am Namensraum, die durch die Beispiele vorgenommen werden (z.B. die Bindung neuer Variablen), werden nach der Ausführung des Tests in
globsreflektiert.
- name¶
Ein String-Name, der die
DocTestidentifiziert. Typischerweise ist dies der Name des Objekts oder der Datei, aus der der Test extrahiert wurde.
- filename¶
Der Name der Datei, aus der diese
DocTestextrahiert wurde; oderNone, wenn der Dateiname unbekannt ist oder dieDocTestnicht aus einer Datei extrahiert wurde.
- lineno¶
Die Zeilennummer in
filename, wo dieseDocTestbeginnt, oderNone, wenn die Zeilennummer nicht verfügbar ist. Diese Zeilennummer ist relativ zum Anfang der Datei nullbasiert.
- docstring¶
Der String, aus dem der Test extrahiert wurde, oder
None, wenn der String nicht verfügbar ist oder der Test nicht aus einem String extrahiert wurde.
Example-Objekte¶
- class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)¶
Ein einzelnes interaktives Beispiel, bestehend aus einer Python-Anweisung und ihrer erwarteten Ausgabe. Die Konstruktorargumente werden zur Initialisierung der Attribute mit denselben Namen verwendet.
Exampledefiniert die folgenden Attribute. Sie werden vom Konstruktor initialisiert und sollten nicht direkt modifiziert werden.- source¶
Ein String, der den Quellcode des Beispiels enthält. Dieser Quellcode besteht aus einer einzelnen Python-Anweisung und endet immer mit einem Zeilenumbruch; der Konstruktor fügt einen Zeilenumbruch hinzu, wenn nötig.
- want¶
Die erwartete Ausgabe der Ausführung des Quellcodes des Beispiels (entweder von stdout oder ein Traceback im Falle einer Ausnahme).
wantendet mit einem Zeilenumbruch, es sei denn, es wird keine Ausgabe erwartet, in welchem Fall es ein leerer String ist. Der Konstruktor fügt bei Bedarf einen Zeilenumbruch hinzu.
- exc_msg¶
Die Ausnahme-Nachricht, die vom Beispiel generiert wird, wenn von dem Beispiel erwartet wird, dass es eine Ausnahme generiert; oder
None, wenn keine Ausnahme erwartet wird. Diese Ausnahme-Nachricht wird mit dem Rückgabewert vontraceback.format_exception_only()verglichen.exc_msgendet mit einem Zeilenumbruch, es sei denn, es istNone. Der Konstruktor fügt bei Bedarf einen Zeilenumbruch hinzu.
- lineno¶
Die Zeilennummer in dem String, der dieses Beispiel enthält, an dem das Beispiel beginnt. Diese Zeilennummer ist nullbasiert relativ zum Anfang des enthaltenden Strings.
- indent¶
Die Einrückung des Beispiels im enthaltenden String, d.h. die Anzahl der Leerzeichen, die dem ersten Prompt des Beispiels vorangestellt sind.
- options¶
Ein Dictionary, das Options-Flags auf
TrueoderFalseabbildet, das verwendet wird, um Standardoptionen für dieses Beispiel zu überschreiben. Alle Options-Flags, die nicht in diesem Dictionary enthalten sind, behalten ihren Standardwert (wie durch dieDocTestRunner-eigenen optionflags angegeben). Standardmäßig sind keine Optionen gesetzt.
DocTestFinder-Objekte¶
- class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)¶
Eine Verarbeitungsklasse, die verwendet wird, um die
DocTests zu extrahieren, die für ein gegebenes Objekt relevant sind, aus seinem Docstring und den Docstrings seiner enthaltenen Objekte.DocTests können aus Modulen, Klassen, Funktionen, Methoden, Statischen Methoden, Klassenmethoden und Properties extrahiert werden.Das optionale Argument verbose kann verwendet werden, um die vom Finder durchsuchten Objekte anzuzeigen. Es ist standardmäßig auf
Falsegesetzt (keine Ausgabe).Das optionale Argument parser gibt das
DocTestParser-Objekt (oder eine Drop-in-Ersetzung) an, das verwendet wird, um Doctests aus Docstrings zu extrahieren.Wenn das optionale Argument recurse falsch ist, dann untersucht
DocTestFinder.find()nur das gegebene Objekt und nicht dessen enthaltene Objekte.Wenn das optionale Argument exclude_empty falsch ist, dann schließt
DocTestFinder.find()Tests für Objekte mit leeren Docstrings ein.DocTestFinderdefiniert die folgende Methode.- find(obj[, name][, module][, globs][, extraglobs])¶
Gibt eine Liste der
DocTests zurück, die im Docstring von obj oder in den Docstrings seiner enthaltenen Objekte definiert sind.Das optionale Argument name gibt den Namen des Objekts an; dieser Name wird verwendet, um Namen für die zurückgegebenen
DocTests zu konstruieren. Wenn name nicht angegeben ist, wirdobj.__name__verwendet.Der optionale Parameter module ist das Modul, das das gegebene Objekt enthält. Wenn das Modul nicht angegeben ist oder
Noneist, versucht der Test-Finder, das korrekte Modul automatisch zu ermitteln. Das Modul des Objekts wird verwendetAls Standard-Namensraum, wenn globs nicht angegeben ist.
Um zu verhindern, dass der DocTestFinder DocTests aus Objekten extrahiert, die aus anderen Modulen importiert wurden. (Enthaltene Objekte mit anderen Modulen als module werden ignoriert.)
Um den Namen der Datei zu finden, die das Objekt enthält.
Um die Zeilennummer des Objekts in seiner Datei zu finden.
Wenn module
Falseist, wird keine Modulsuchung durchgeführt. Dies ist obskur und hauptsächlich zum Testen von Doctest selbst nützlich: Wenn moduleFalseist oderNoneist, aber nicht automatisch gefunden werden kann, dann gehören alle Objekte zum (nicht existenten) Modul, sodass alle enthaltenen Objekte (rekursiv) nach Doctests durchsucht werden.Die Globale für jede
DocTestwird durch die Kombination von globs und extraglobs gebildet (Bindungen in extraglobs überschreiben Bindungen in globs). Für jedeDocTestwird eine neue flache Kopie des Global-Dictionarys erstellt. Wenn globs nicht angegeben ist, wird standardmäßig auf das__dict__des Moduls zurückgegriffen, falls angegeben, ansonsten auf{}. Wenn extraglobs nicht angegeben ist, wird standardmäßig auf{}zurückgegriffen.
DocTestParser-Objekte¶
- class doctest.DocTestParser¶
Eine Verarbeitungsklasse, die verwendet wird, um interaktive Beispiele aus einem String zu extrahieren und sie zur Erstellung eines
DocTest-Objekts zu verwenden.DocTestParserdefiniert die folgenden Methoden.- get_doctest(string, globs, name, filename, lineno)¶
Extrahiert alle Doctest-Beispiele aus dem gegebenen String und sammelt sie in einem
DocTest-Objekt.globs, name, filename und lineno sind Attribute für das neue
DocTest-Objekt. Weitere Informationen finden Sie in der Dokumentation vonDocTest.
- get_examples(string, name='<string>')¶
Extrahiert alle Doctest-Beispiele aus dem gegebenen String und gibt sie als Liste von
Example-Objekten zurück. Zeilennummern sind nullbasiert. Das optionale Argument name ist ein Name, der diesen String identifiziert, und wird nur für Fehlermeldungen verwendet.
- parse(string, name='<string>')¶
Teilt den gegebenen String in Beispiele und dazwischen liegenden Text auf und gibt sie als Liste von abwechselnden
Examples und Strings zurück. Zeilennummern für dieExamples sind nullbasiert. Das optionale Argument name ist ein Name, der diesen String identifiziert, und wird nur für Fehlermeldungen verwendet.
TestResults-Objekte¶
DocTestRunner-Objekte¶
- class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)¶
Eine Verarbeitungsklasse, die verwendet wird, um die interaktiven Beispiele in einer
DocTestauszuführen und zu verifizieren.Der Vergleich zwischen erwarteten und tatsächlichen Ausgaben erfolgt durch einen
OutputChecker. Dieser Vergleich kann mit einer Reihe von Options-Flags angepasst werden; siehe Abschnitt Option Flags für weitere Informationen. Wenn die Options-Flags nicht ausreichen, kann der Vergleich auch durch Übergabe einer Unterklasse vonOutputCheckeran den Konstruktor angepasst werden.Die Ausgaben des Testläufers können auf zwei Arten gesteuert werden. Erstens kann eine Ausgabefunktion an
run()übergeben werden; diese Funktion wird mit Zeichenketten aufgerufen, die angezeigt werden sollen. Sie ist standardmäßigsys.stdout.write. Wenn das Erfassen der Ausgabe nicht ausreicht, kann die Anzeigeausgabe auch durch Unterklasse von DocTestRunner und Überschreiben der Methodenreport_start(),report_success(),report_unexpected_exception()undreport_failure()angepasst werden.Das optionale Schlüsselwortargument checker gibt das
OutputChecker-Objekt (oder einen Drop-in-Ersatz) an, das zum Vergleichen der erwarteten Ausgaben mit den tatsächlichen Ausgaben von Doctest-Beispielen verwendet werden soll.Das optionale Schlüsselwortargument verbose steuert die Ausführlichkeit des
DocTestRunner. Wenn verboseTrueist, werden Informationen über jedes Beispiel gedruckt, während es ausgeführt wird. Wenn verboseFalseist, werden nur Fehler gedruckt. Wenn verbose nicht angegeben ist oderNoneist, wird die ausführliche Ausgabe verwendet, wenn der Befehlszeilenschalter-vverwendet wird.Das optionale Schlüsselwortargument optionflags kann verwendet werden, um zu steuern, wie der Testläufer erwartete Ausgaben mit tatsächlichen Ausgaben vergleicht und wie Fehler angezeigt werden. Weitere Informationen finden Sie im Abschnitt Option Flags.
Der Testläufer sammelt Statistiken. Die aggregierte Anzahl von versuchten, fehlgeschlagenen und übersprungenen Beispielen ist auch über die Attribute
tries,failuresundskipsverfügbar. Die Methodenrun()undsummarize()geben eineTestResults-Instanz zurück.DocTestRunnerdefiniert die folgenden Methoden- report_start(out, test, example)¶
Meldet, dass der Testläufer das gegebene Beispiel verarbeiten wird. Diese Methode ist vorhanden, um Unterklassen von
DocTestRunnerdie Anpassung ihrer Ausgabe zu ermöglichen; sie sollte nicht direkt aufgerufen werden.example ist das zu verarbeitende Beispiel. test ist der Test, der example enthält. out ist die Ausgabefunktion, die an
DocTestRunner.run()übergeben wurde.
- report_success(out, test, example, got)¶
Meldet, dass das gegebene Beispiel erfolgreich ausgeführt wurde. Diese Methode ist vorhanden, um Unterklassen von
DocTestRunnerdie Anpassung ihrer Ausgabe zu ermöglichen; sie sollte nicht direkt aufgerufen werden.example ist das zu verarbeitende Beispiel. got ist die tatsächliche Ausgabe des Beispiels. test ist der Test, der example enthält. out ist die Ausgabefunktion, die an
DocTestRunner.run()übergeben wurde.
- report_failure(out, test, example, got)¶
Meldet, dass das gegebene Beispiel fehlgeschlagen ist. Diese Methode ist vorhanden, um Unterklassen von
DocTestRunnerdie Anpassung ihrer Ausgabe zu ermöglichen; sie sollte nicht direkt aufgerufen werden.example ist das zu verarbeitende Beispiel. got ist die tatsächliche Ausgabe des Beispiels. test ist der Test, der example enthält. out ist die Ausgabefunktion, die an
DocTestRunner.run()übergeben wurde.
- report_unexpected_exception(out, test, example, exc_info)¶
Meldet, dass das gegebene Beispiel eine unerwartete Ausnahme ausgelöst hat. Diese Methode ist vorhanden, um Unterklassen von
DocTestRunnerdie Anpassung ihrer Ausgabe zu ermöglichen; sie sollte nicht direkt aufgerufen werden.example ist das zu verarbeitende Beispiel. exc_info ist ein Tupel mit Informationen über die unerwartete Ausnahme (wie von
sys.exc_info()zurückgegeben). test ist der Test, der example enthält. out ist die Ausgabefunktion, die anDocTestRunner.run()übergeben wurde.
- run(test, compileflags=None, out=None, clear_globs=True)¶
Führt die Beispiele in test (einem
DocTest-Objekt) aus und zeigt die Ergebnisse mit der Writer-Funktion out an. Gibt eineTestResults-Instanz zurück.Die Beispiele werden im Namensraum
test.globsausgeführt. Wenn clear_globs wahr ist (Standard), wird dieser Namensraum nach der Ausführung des Tests gelöscht, um die Speicherbereinigung zu unterstützen. Wenn Sie den Namensraum nach Abschluss des Tests untersuchen möchten, verwenden Sie clear_globs=False.compileflags gibt den Satz von Flags an, der vom Python-Compiler beim Ausführen der Beispiele verwendet werden soll. Wenn nicht angegeben, wird standardmäßig der Satz von zukünftigen Import-Flags verwendet, die für globs gelten.
Die Ausgabe jedes Beispiels wird mit dem Output-Checker des
DocTestRunnerüberprüft, und die Ergebnisse werden von den MethodenDocTestRunner.report_*()formatiert.
- summarize(verbose=None)¶
Gibt eine Zusammenfassung aller Testfälle aus, die von diesem DocTestRunner ausgeführt wurden, und gibt eine
TestResults-Instanz zurück.Das optionale Argument verbose steuert die Detailtiefe der Zusammenfassung. Wenn die Ausführlichkeit nicht angegeben ist, wird die Ausführlichkeit des
DocTestRunnerverwendet.
DocTestParserhat die folgenden Attribute- tries¶
Anzahl der versuchten Beispiele.
- failures¶
Anzahl der fehlgeschlagenen Beispiele.
- skips¶
Anzahl der übersprungenen Beispiele.
Hinzugefügt in Version 3.13.
OutputChecker-Objekte¶
- class doctest.OutputChecker¶
Eine Klasse, die verwendet wird, um zu überprüfen, ob die tatsächliche Ausgabe eines Doctest-Beispiels mit der erwarteten Ausgabe übereinstimmt.
OutputCheckerdefiniert zwei Methoden:check_output(), die ein gegebenes Paar von Ausgaben vergleicht undTruezurückgibt, wenn sie übereinstimmen; undoutput_difference(), die eine Zeichenkette zurückgibt, die die Unterschiede zwischen zwei Ausgaben beschreibt.OutputCheckerdefiniert die folgenden Methoden- check_output(want, got, optionflags)¶
Gibt
Truezurück, wenn die tatsächliche Ausgabe eines Beispiels (got) mit der erwarteten Ausgabe (want) übereinstimmt. Diese Zeichenketten werden immer als übereinstimmend betrachtet, wenn sie identisch sind; aber abhängig von den vom Testläufer verwendeten Optionsflags sind auch mehrere nicht-exakte Übereinstimmungstypen möglich. Siehe Abschnitt Option Flags für weitere Informationen über Optionsflags.
- output_difference(example, got, optionflags)¶
Gibt eine Zeichenkette zurück, die die Unterschiede zwischen der erwarteten Ausgabe für ein gegebenes Beispiel (example) und der tatsächlichen Ausgabe (got) beschreibt. optionflags ist die Menge der Optionsflags, die zum Vergleichen von want und got verwendet werden.
Debugging¶
Doctest bietet mehrere Mechanismen zum Debuggen von Doctest-Beispielen
Mehrere Funktionen konvertieren Doctests in ausführbare Python-Programme, die unter dem Python-Debugger
pdbausgeführt werden können.Die Klasse
DebugRunnerist eine Unterklasse vonDocTestRunner, die für das erste fehlerhafte Beispiel eine Ausnahme auslöst, die Informationen über dieses Beispiel enthält. Diese Informationen können für das Post-Mortem-Debugging des Beispiels verwendet werden.Die von
DocTestSuite()generiertenunittest-Fälle unterstützen die vonunittest.TestCasedefinierte Methodedebug().Sie können einen Aufruf von
pdb.set_trace()in ein Doctest-Beispiel einfügen, und Sie werden beim Ausführen dieser Zeile in den Python-Debugger gelangen. Dann können Sie die aktuellen Werte von Variablen usw. inspizieren. Angenommen,a.pyenthält nur diesen Modul-Docstring""" >>> def f(x): ... g(x*2) >>> def g(x): ... print(x+3) ... import pdb; pdb.set_trace() >>> f(3) 9 """
Dann könnte eine interaktive Python-Sitzung wie folgt aussehen:
>>> import a, doctest >>> doctest.testmod(a) --Return-- > <doctest a[1]>(3)g()->None -> import pdb; pdb.set_trace() (Pdb) list 1 def g(x): 2 print(x+3) 3 -> import pdb; pdb.set_trace() [EOF] (Pdb) p x 6 (Pdb) step --Return-- > <doctest a[0]>(2)f()->None -> g(x*2) (Pdb) list 1 def f(x): 2 -> g(x*2) [EOF] (Pdb) p x 3 (Pdb) step --Return-- > <doctest a[2]>(1)?()->None -> f(3) (Pdb) cont (0, 3) >>>
Funktionen, die Doctests in Python-Code konvertieren und den synthetisierten Code möglicherweise unter dem Debugger ausführen
- doctest.script_from_examples(s)¶
Konvertiert Text mit Beispielen in ein Skript.
Argument s ist eine Zeichenkette, die Doctest-Beispiele enthält. Die Zeichenkette wird in ein Python-Skript konvertiert, wobei Doctest-Beispiele in s in normalen Code und alles andere in Python-Kommentare konvertiert wird. Das generierte Skript wird als Zeichenkette zurückgegeben. Zum Beispiel,
import doctest print(doctest.script_from_examples(r""" Set x and y to 1 and 2. >>> x, y = 1, 2 Print their sum: >>> print(x+y) 3 """))
zeigt
# Set x and y to 1 and 2. x, y = 1, 2 # # Print their sum: print(x+y) # Expected: ## 3
Diese Funktion wird intern von anderen Funktionen (siehe unten) verwendet, kann aber auch nützlich sein, wenn Sie eine interaktive Python-Sitzung in ein Python-Skript transformieren möchten.
- doctest.testsource(module, name)¶
Konvertiert den Doctest für ein Objekt in ein Skript.
Argument module ist ein Modulobjekt oder der gepunktete Name eines Moduls, das das Objekt enthält, dessen Doctests von Interesse sind. Argument name ist der Name (innerhalb des Moduls) des Objekts mit den interessierenden Doctests. Das Ergebnis ist eine Zeichenkette, die den Docstring des Objekts, konvertiert in ein Python-Skript, wie für
script_from_examples()oben beschrieben, enthält. Wenn zum Beispiel das Modula.pyeine Top-Level-Funktionf()enthält, dannimport a, doctest print(doctest.testsource(a, "a.f"))
druckt eine Skriptversion des Docstrings der Funktion
f(), wobei Doctests in Code konvertiert und der Rest in Kommentaren platziert wird.
- doctest.debug(module, name, pm=False)¶
Debuggt die Doctests für ein Objekt.
Die Argumente module und name sind die gleichen wie für die Funktion
testsource()oben. Das synthetisierte Python-Skript für den Docstring des benannten Objekts wird in eine temporäre Datei geschrieben, und dann wird diese Datei unter der Kontrolle des Python-Debuggerspdbausgeführt.Eine flache Kopie von
module.__dict__wird sowohl für den lokalen als auch für den globalen Ausführungskontext verwendet.Das optionale Argument pm steuert, ob Post-Mortem-Debugging verwendet wird. Wenn pm einen wahren Wert hat, wird die Skriptdatei direkt ausgeführt und der Debugger wird erst aktiv, wenn das Skript durch Auslösen einer unbehandelten Ausnahme beendet wird. Wenn dies geschieht, wird Post-Mortem-Debugging über
pdb.post_mortem()aufgerufen, wobei das Traceback-Objekt der unbehandelten Ausnahme übergeben wird. Wenn pm nicht angegeben oder falsch ist, wird das Skript von Anfang an unter dem Debugger ausgeführt, indem ein entsprechenderexec()-Aufruf anpdb.run()übergeben wird.
- doctest.debug_src(src, pm=False, globs=None)¶
Debuggt die Doctests in einer Zeichenkette.
Dies ist wie die Funktion
debug()oben, mit dem Unterschied, dass eine Zeichenkette mit Doctest-Beispielen direkt über das Argument src angegeben wird.Das optionale Argument pm hat die gleiche Bedeutung wie in der Funktion
debug()oben.Das optionale Argument globs gibt ein Wörterbuch an, das sowohl als lokaler als auch als globaler Ausführungskontext verwendet wird. Wenn nicht angegeben oder
None, wird ein leeres Wörterbuch verwendet. Wenn angegeben, wird eine flache Kopie des Wörterbuchs verwendet.
Die Klasse DebugRunner und die speziellen Ausnahmen, die sie möglicherweise auslöst, sind vor allem für Autoren von Testframeworks von Interesse und werden hier nur skizziert. Siehe den Quellcode und insbesondere den Docstring von DebugRunner (der ein Doctest ist!) für weitere Details
- class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)¶
Eine Unterklasse von
DocTestRunner, die eine Ausnahme auslöst, sobald ein Fehler auftritt. Wenn eine unerwartete Ausnahme auftritt, wird eineUnexpectedException-Ausnahme ausgelöst, die den Test, das Beispiel und die ursprüngliche Ausnahme enthält. Wenn die Ausgabe nicht übereinstimmt, wird eineDocTestFailure-Ausnahme ausgelöst, die den Test, das Beispiel und die tatsächliche Ausgabe enthält.Informationen zu den Konstruktorparametern und Methoden finden Sie in der Dokumentation für
DocTestRunnerim Abschnitt Advanced API.
Es gibt zwei Ausnahmen, die von Instanzen von DebugRunner ausgelöst werden können
- exception doctest.DocTestFailure(test, example, got)¶
Eine Ausnahme, die von
DocTestRunnerausgelöst wird, um zu signalisieren, dass die tatsächliche Ausgabe eines Doctest-Beispiels nicht mit seiner erwarteten Ausgabe übereinstimmt. Die Konstruktorargumente werden zur Initialisierung der gleichnamigen Attribute verwendet.
DocTestFailure definiert die folgenden Attribute
- DocTestFailure.got¶
Die tatsächliche Ausgabe des Beispiels.
- exception doctest.UnexpectedException(test, example, exc_info)¶
Eine Ausnahme, die von
DocTestRunnerausgelöst wird, um zu signalisieren, dass ein Doctest-Beispiel eine unerwartete Ausnahme ausgelöst hat. Die Konstruktorargumente werden zur Initialisierung der gleichnamigen Attribute verwendet.
UnexpectedException definiert die folgenden Attribute
- UnexpectedException.test¶
Das
DocTest-Objekt, das gerade ausgeführt wurde, als das Beispiel fehlschlug.
- UnexpectedException.exc_info¶
Ein Tupel mit Informationen über die unerwartete Ausnahme, wie von
sys.exc_info()zurückgegeben.
Soapbox¶
Wie in der Einleitung erwähnt, hat doctest inzwischen drei Hauptanwendungsbereiche
Überprüfung von Beispielen in Docstrings.
Regressionstests.
Ausführbare Dokumentation / Literaturbasierte Tests.
Diese Verwendungszwecke haben unterschiedliche Anforderungen, und es ist wichtig, sie zu unterscheiden. Insbesondere das Füllen Ihrer Docstrings mit obskuren Testfällen macht schlechte Dokumentation.
Bei der Erstellung eines Docstrings sollten Sie die Beispiel-Docstrings sorgfältig auswählen. Es gibt eine Kunst darin, die erlernt werden muss – sie ist anfangs vielleicht nicht natürlich. Beispiele sollten einen echten Mehrwert für die Dokumentation bieten. Ein gutes Beispiel kann oft viele Worte wert sein. Wenn mit Sorgfalt durchgeführt, werden die Beispiele für Ihre Benutzer von unschätzbarem Wert sein und die Zeit, die für ihre Sammlung benötigt wird, viele Male wieder hereinholen, wenn die Jahre vergehen und sich Dinge ändern. Ich bin immer noch erstaunt, wie oft eines meiner doctest-Beispiele nach einer „harmlosen“ Änderung nicht mehr funktioniert.
Doctest eignet sich auch hervorragend für Regressionstests, insbesondere wenn Sie nicht an erläuterndem Text sparen. Durch die Verflechtung von Prosa und Beispielen wird es wesentlich einfacher, den Überblick zu behalten, was tatsächlich getestet wird und warum. Wenn ein Test fehlschlägt, kann eine gute Prosa es erheblich erleichtern, das Problem zu erkennen und wie es behoben werden sollte. Es stimmt, dass Sie beim codebasierten Testen ausführliche Kommentare schreiben könnten, aber nur wenige Programmierer tun dies. Viele haben festgestellt, dass die Verwendung von Doctest-Ansätzen stattdessen zu wesentlich klareren Tests führt. Vielleicht liegt das einfach daran, dass Doctest das Schreiben von Prosa etwas einfacher macht als das Schreiben von Code, während das Schreiben von Kommentaren in Code etwas schwieriger ist. Ich denke, es geht tiefer als das: Die natürliche Einstellung beim Schreiben eines doctest-basierten Tests ist, dass man die Feinheiten seiner Software erklären und mit Beispielen veranschaulichen möchte. Dies wiederum führt natürlich zu Testdateien, die mit den einfachsten Funktionen beginnen und logisch zu Komplikationen und Sonderfällen fortschreiten. Das Ergebnis ist eine zusammenhängende Erzählung anstelle einer Sammlung isolierter Funktionen, die scheinbar zufällig isolierte Funktionalitäten testen. Es ist eine andere Haltung und führt zu anderen Ergebnissen, die die Unterscheidung zwischen Testen und Erklären verwischen.
Regressionstests sollten am besten auf dedizierte Objekte oder Dateien beschränkt werden. Es gibt verschiedene Optionen für die Organisation von Tests
Schreiben Sie Textdateien, die Testfälle als interaktive Beispiele enthalten, und testen Sie die Dateien mit
testfile()oderDocFileSuite(). Dies wird empfohlen, ist aber am einfachsten für neue Projekte, die von Anfang an für die Verwendung von Doctest konzipiert wurden.Definieren Sie Funktionen namens
_regrtest_topic, die aus einzelnen Docstrings bestehen und Testfälle für die benannten Themen enthalten. Diese Funktionen können in derselben Datei wie das Modul enthalten sein oder in eine separate Testdatei ausgelagert werden.Definieren Sie ein
__test__-Wörterbuch, das von Regressionstest-Themen auf Docstrings mit Testfällen abgebildet wird.
Wenn Sie Ihre Tests in einem Modul platziert haben, kann das Modul selbst der Test-Runner sein. Wenn ein Test fehlschlägt, können Sie Ihren Test-Runner so arrangieren, dass er während des Debuggens des Problems nur den fehlschlagenden Doctest erneut ausführt. Hier ist ein minimales Beispiel für einen solchen Test-Runner
if __name__ == '__main__':
import doctest
flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
if len(sys.argv) > 1:
name = sys.argv[1]
if name in globals():
obj = globals()[name]
else:
obj = __test__[name]
doctest.run_docstring_examples(obj, globals(), name=name,
optionflags=flags)
else:
fail, total = doctest.testmod(optionflags=flags)
print(f"{fail} failures out of {total} tests")
Fußnoten