doctest
— Exemples de tests interactifs en Python¶
Code source : Lib/doctest.py
Le module doctest
cherche des extraits de texte ressemblant à des sessions Python interactives avant de les exécuter, de façon à vérifier que le fonctionnement correspond exactement à la description. Voici quelques cas d'utilisation de doctest :
Vérifier que les docstrings d'un module sont à jour en vérifiant que tous les exemples interactifs fonctionnent toujours tels que décrits.
Réaliser un test de régression en vérifiant que les exemples interactifs provenant d'un fichier de test ou d'un objet de test fonctionnent comme prévu.
Rédiger de la documentation sous forme de tutoriel pour un paquet, avec une abondance d'exemples ayant des entrées et des sorties. On pourrait voir ça comme des tests « dans le texte » ou de la « documentation exécutable », selon le point de vue.
Voici un petit exemple d'un module qui soit tout de même complet :
"""
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()
L'exécution du fichier example.py
directement à partir de la ligne de commande démontre la magie de doctest
:
$ python example.py
$
Il n'y a pas de sortie ! C'est normal, cela signifie que tous les exemples fonctionnent. Passez -v
au script pour que doctest
affiche un journal détaillé de ce qui a été essayé, avant d'afficher un résumé à la fin :
$ 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
Et ainsi de suite, jusqu'à ce qu'on atteigne :
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.
$
That's all you need to know to start making productive use of doctest
!
Jump in. The following sections provide full details. Note that there are many
examples of doctests in the standard Python test suite and libraries.
Especially useful examples can be found in the standard test file
Lib/test/test_doctest/test_doctest.py
.
Utilisation simple : vérifier des exemples dans des docstrings¶
Le plus simple pour commencer à utiliser doctest (mais pas nécessairement la façon avec laquelle vous continuerez) est de terminer chaque module M
avec :
if __name__ == "__main__":
import doctest
doctest.testmod()
doctest
examine alors les docstrings dans le module M
.
Exécuter le module comme un script a comme conséquence d'exécuter et de vérifier les exemples dans les docstrings :
python M.py
Ceci n'affiche rien à moins qu'un exemple échoue ; le cas échéant, les exemples défaillants et les causes du ou des échecs sont affichés sur stdout, et la ligne finale de la sortie est ***Test Failed*** *N failures*.
, où N est le nombre d'exemples défaillants.
À la place, exécutez-la avec l'option de ligne de commande -v
:
python M.py -v
alors, un rapport détaillé de tous les exemples faisant partie de l'essai est affiché sur la sortie standard, accompagné à la fin de leurs résumés.
Vous pouvez activer le mode verbeux en passant verbose=True
à testmod()
, ou vous le désactiver en lui passant verbose=False
. Dans ces deux cas, sys.argv
n'est pas inspecté par testmod()
(ainsi, lui passer -v
ou pas n'a aucun effet).
Il y a un raccourci pour exécuter testmod()
à partir de la ligne de commande. Vous demandez à l'interpréteur Python d'exécuter le module doctest directement à partir de la bibliothèque standard afin de passer le ou les noms des modules à partir de la ligne de commande ainsi :
python -m doctest -v example.py
Ceci importera example.py
comme un module autonome et exécutera testmod()
sur celui-ci. Notez que ceci peut ne pas fonctionner si le fichier fait partie d'un paquet et importe d'autres sous-modules de ce paquet.
Pour plus d'informations sur testmod()
, consultez la section API de base.
Utilisation simple : vérifier des exemples dans un fichier texte¶
Une autre application simple de doctest est de tester des exemples interactifs dans un fichier texte. Ceci est fait avec la fonction testfile()
:
import doctest
doctest.testfile("example.txt")
Ce court script exécute et vérifie chacun des exemples Python interactifs contenus dans le fichier example.txt
. Le contenu du fichier est traité comme une seule docstring géante ; le fichier n'a pas besoin de contenir un programme Python ! Par exemple, prenons un fichier example.txt
contenant :
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
Exécuter doctest.testfile("example.txt")
recherche les erreurs dans cette documentation :
File "./example.txt", line 14, in example.txt
Failed example:
factorial(6)
Expected:
120
Got:
720
Comme pour testmod()
, testfile()
n'affichera rien sauf si un exemple échoue. Si un exemple échoue, alors le ou les exemples défaillants et leurs causes sont affichés sur stdout, dans le même format que testmod()
.
Par défaut, testfile()
cherche les fichiers dans le répertoire où se situe le module qui l'appelle. Consultez la section API de base pour une description des options de ligne de commande à utiliser afin de chercher dans d'autres répertoires.
Comme pour testmod()
, la verbosité de testfile()
peut être ajustée avec l'option de ligne de commande -v
ou avec le mot clé verbose.
Il y a un raccourci pour exécuter testfile()
à partir de la ligne de commande. Demandez à l'interpréteur Python d'exécuter le module doctest directement à partir de la bibliothèque standard et de passer le ou les noms des modules à partir de la ligne de commande ainsi :
python -m doctest -v example.txt
Puisque le nom du fichier ne se termine pas par .py
, doctest
en déduit qu'il s'exécute à l'aide de testfile()
, et non pas testmod()
.
Pour plus d'information sur testfile()
, consultez la section API de base.
Comment ça marche¶
Cette section examine en détail le fonctionnement de doctest : quelles docstrings sont considérées, comment sont trouvés les exemples interactifs, quel est le contexte d'exécution sélectionné, comment les exceptions sont gérées, et de quelles façons les options de ligne de commande peuvent être utilisées pour définir le comportement. Ceci est l'information dont vous avez besoin pour écrire des exemples doctest ; pour de l'information sur l'exécution de doctest sur ces exemples, consultez les sections suivantes.
Quelles docstrings sont considérées ?¶
Les docstrings du module, de toutes les fonctions, classes, et méthodes sont cherchées. Les objets qui sont importés dans le module ne sont pas cherchés.
In addition, there are cases when you want tests to be part of a module but not part
of the help text, which requires that the tests not be included in the docstring.
Doctest looks for a module-level variable called __test__
and uses it to locate other
tests. If M.__test__
exists, it must be a dict, and each
entry maps a (string) name to a function object, class object, or string.
Function and class object docstrings found from M.__test__
are searched, and
strings are treated as if they were docstrings. In output, a key K
in
M.__test__
appears with name M.__test__.K
.
For example, place this block of code at the top of example.py
:
__test__ = {
'numbers': """
>>> factorial(6)
720
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
}
The value of example.__test__["numbers"]
will be treated as a
docstring and all the tests inside it will be run. It is
important to note that the value can be mapped to a function,
class object, or module; if so, doctest
searches them recursively for docstrings, which are then scanned for tests.
Toute classe trouvée est ainsi cherchée récursivement, afin de tester les docstrings contenues dans leurs méthodes et leurs classes imbriquées.
Comment les exemples docstring sont-ils identifiés ?¶
Dans la plupart des cas, un copier-coller d'une séance interactive de console fonctionne bien, mais doctest n'essaye pas de faire une simulation exacte d'un shell Python spécifique.
>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
... print("yes")
... else:
... print("no")
... print("NO")
... print("NO!!!")
...
no
NO
NO!!!
>>>
Toute sortie souhaitée doit immédiatement suivre le dernier '>>> '
ou le dernier '... '
contenant le code, et la sortie souhaitée, s'il y en a une, s'étend jusqu'au prochain '>>> '
ou à la prochaine ligne vide.
En détail :
La sortie souhaitée ne peut pas contenir une ligne vide, puisque contenir une telle ligne signale la fin de la sortie souhaitée. Si la sortie souhaitée doit contenir une ligne vide, ajoutez
<BLANKLINE>
dans votre exemple doctest à chaque endroit où une ligne vide est souhaitée.Tous les caractères de tabulation insécables (hard tab characters) sont convertis en espaces, en utilisant des taquets de tabulation de 8 espaces. Les tabulations se trouvant dans la sortie générée par le code test ne sont pas modifiées. Comme tout caractère de tabulation insécable est converti, ceci veut dire que si le code de sortie inclut des caractères de tabulation insécables, alors la seule façon que le doctest peut réussir est si l'option
NORMALIZE_WHITESPACE
ou si directive a cours. De façon alternative, le test peut être ré-écrit afin de capturer la sortie et de la comparer à un ensemble de valeurs attendues, et ce, en tant qu'étape du test. Cette gestion des tabulations à la source a été obtenue suite à un processus d'essais et d'erreurs ; il a été démontré que c'était là la façon de les gérer qui soit la moins susceptible de générer des erreurs. Il est possible d'utiliser un algorithme différent pour la gestion des tabulations en rédigeant une classe sur mesureDocTestParser
.La sortie vers stdout est capturée, mais pas la sortie vers stderr (les traces d'appel sont capturées par d'autres moyens).
Si vous souhaitez conserver les barres obliques inversées telles quelles lorsque vous terminez une ligne avec une barre oblique inversée dans une séance interactive, ou quand vous utilisez une telle barre pour toute autre raison, vous devez utiliser une docstring brute :
>>> def f(x): ... r'''Backslashes in a raw docstring: m\n''' ... >>> print(f.__doc__) Backslashes in a raw docstring: m\n
Sinon, la barre oblique inversée est interprétée comme faisant partie de la chaîne de caractères. Par exemple, le
\n
ci-dessus est interprété comme un caractère de saut de ligne. De façon alternative, vous pouvez doubler chaque barre oblique inversée dans la version doctest (et n'utilisez pas dans ce cas de docstring brute) :>>> def f(x): ... '''Backslashes in a raw docstring: m\\n''' ... >>> print(f.__doc__) Backslashes in a raw docstring: m\n
La colonne de départ n'a pas d'importance :
>>> assert "Easy!" >>> import math >>> math.floor(1.9) 1
et autant d'espaces sont retirés de la sortie attendue qu'il y avait d'espaces avant la ligne commençant par
'>>> '
.
Quel est le contexte d'exécution ?¶
Par défaut, chaque fois que doctest
trouve une docstring à tester, il utilise une copie superficielle des variables globales de M
, de telle façon que l'exécution de tests ne change pas les variables globales réelles du module et que l'exécution d'un unique test dans M
ne puisse laisser traîner des miettes pouvant accidentellement causer la réussite d'un autre test. Ceci signifie que les exemples peuvent utiliser librement n'importe quel nom défini au niveau supérieur dans M
ainsi que les noms définis précédemment dans la docstring en cours d'exécution. Les exemples ne peuvent voir les noms définis dans d'autres docstrings.
Vous pouvez forcer l'utilisation de votre propre dict comme contexte d'exécution en passant globs=your_dict
à testmod()
ou encore, à testfile()
.
Qu'en est-il des exceptions ?¶
Pas de problèmes, tant que la trace d'appels est la seule sortie produite par l'exemple : il suffit d'ajouter la trace. [1] Comme les traces d'appels contiennent des détails qui sont sujets à changement rapide (par exemple, le chemin exact vers un fichier et les numéros de ligne), ceci est un cas où doctest fait un effort pour être flexible dans ce qu'il accepte.
Exemple simple :
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
Ce doctest réussit si ValueError
est levée, avec le détail list.remote(x): x not in list
tel que montré.
La sortie attendue pour une exception doit commencer par un en-tête de trace d'appels, qui peut être l'une des deux lignes suivantes, avec la même indentation que la première ligne de l'exemple :
Traceback (most recent call last):
Traceback (innermost last):
L'en-tête de la trace d'appels est suivi par une pile optionnelle de trace d'appels, dont le contenu est ignoré par doctest. La trace d'appels est habituellement omise, ou est copiée verbatim à partir d'une séance interactive.
La pile de trace d'appels est suivie par la partie la plus intéressante : la ou les lignes contenant le type et le détail de l'exception. Ceci est habituellement la dernière ligne de la trace d'appels ; dans le cas où l'exception a un détail sur plusieurs lignes, il est possible de prolonger sur plusieurs lignes :
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: multi
line
detail
Les trois dernières lignes (en commençant par ValueError
) sont comparées avec le type et le détail de l'exception ; tout le reste est ignoré.
La pratique optimale est d'omettre la pile de trace d'appels, à moins que celle-ci ait une valeur significative de documentation de l'exemple. Ainsi, le dernier exemple est probablement meilleur tel qui suit :
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
...
ValueError: multi
line
detail
Prenez note que les traces d'appels sont traitées de façon vraiment particulière. Précisément, dans l'exemple ré-écrit, l'utilisation de ...
est indépendante de l'option doctest ELLIPSIS
. Les points de suspension dans cet exemple peuvent être omis, ou peuvent aussi être trois (ou trois cents) virgules ou chiffres, ou une retranscription indentée d'une parodie de Monty Python.
Quelques détails que vous devriez lire une fois, mais que vous pouvez oublier :
Doctest ne peut pas deviner si votre sortie attendue provient d'une trace d'appels issue d'une exception ou d'un affichage ordinaire. Ainsi, si nous avons un exemple s'attendant à obtenir
ValueError: 42 is prime
, celui-ci réussira peu importe siValueError
est réellement levée ou si l'exemple affiche simplement ce texte de trace d'appels. Dans la pratique, une sortie ordinaire commence rarement par une ligne d'en-tête de trace d'appels ; ainsi, ceci ne pose pas de vrai problème.Chaque ligne de la trace d'appel (s'il y en a) doit soit être indentée d'un niveau supplémentaire au niveau de la première ligne de l'exemple ou doit commencer par un caractère qui ne soit pas alphanumérique. La première ligne suivant l'en-tête de la trace d'appels qui soit indentée similairement et qui commence par un caractère alphanumérique est comprise comme étant le début du détail de l'exception. Bien sûr, ceci fait la chose adéquate pour les traces d'appels véritables.
Lorsque l'option de doctest
IGNORE_EXCEPTION_DETAIL
est définie, tout ce qui suit le point-virgule se trouvant le plus à gauche ainsi que toute information liée au module dans le nom de l'exception sont ignorés.Le shell interactif omet la ligne d'en-tête de la trace d'appels pour certaines erreurs
SyntaxError
. Ceci étant dit, doctest utilise la ligne d'en-tête de la trace d'appels afin de faire une distinction entre les exceptions et les autres types d'erreurs. Ainsi, dans les rares cas où vous avez besoin de tester une erreurSyntaxError
qui omet l'en-tête de la trace d'appels, il vous est nécessaire d'ajouter manuellement la ligne d'en-tête de la trace d'appels à l'exemple de test.
Pour certaines erreurs, Python affiche la position de l'erreur en utilisant le marqueur
^
et des tildes :>>> 1 + None File "<stdin>", line 1 1 + None ~~^~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
Comme les lignes dénotant la position de l'erreur précèdent le type et le détail de l'exception, elles ne sont pas vérifiées par doctest. Par exemple, le test suivant réussira, même si le marqueur
^
n'est pas à la bonne place :>>> 1 + None File "<stdin>", line 1 1 + None ^~~~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
Options de ligne de commande¶
Un ensemble d'options de ligne de commande contrôle différents aspects du comportement de doctest. Pour les options, des noms symboliques sont fournis comme des constantes de module, qui peuvent être composés par un OU bit à bit (bitwise ORed) et passés à diverses fonctions. Les noms peuvent aussi être utilisés dans des instructions doctest, et peuvent être passés à l'interface de ligne de commande de doctest à l'aide de l'option -o
.
Ajouté dans la version 3.4: L'option de ligne de commande -o
.
Le premier groupe d'options définit les sémantiques de test, de façon à contrôler comment doctest décide si la sortie obtenue correspond à la sortie attendue de l'exemple :
- doctest.DONT_ACCEPT_TRUE_FOR_1¶
Par défaut, si un bloc de sortie attendu contient uniquement un
1
, un vrai bloc de sortie contenant uniquement un1
ou unTrue
sera considéré comme étant une correspondance ; de façon similaire, nous avons une correspondance pour0
etFalse
. Lorsque l'optionDONT_ACCEPT_TRUE_FOR_1
est précisée, aucune de ces substitutions n'est acceptée. Le comportement par défaut s'ajuste au fait que Python a changé le type de renvoi de plusieurs fonctions, passant de nombres entiers à des booléens ; les doctests s'attendant à une sortie de « petit entier » (little integer) fonctionnent encore dans ces cas. Cette option disparaîtra probablement, mais pas avant plusieurs années.
- doctest.DONT_ACCEPT_BLANKLINE¶
Par défaut, si un bloc de sortie attendue contient une ligne contenant uniquement la chaîne de caractères
<BLANKLINE>
, alors cette ligne sera en correspondance avec une ligne vide dans la sortie réelle. Puisqu'une véritable ligne vide permet de délimiter la sortie attendue, ceci est la seule façon de communiquer qu'une ligne vide est souhaitée. Lorsque l'optionDONT_ACCEPT_BLANKLINE
est précisée, cette substitution n'est pas permise.
- doctest.NORMALIZE_WHITESPACE¶
Lorsque précisé, toutes les séquences de caractères d'espacement et de caractères de saut de ligne sont traitées comme équivalentes. Toute séquence de caractères d'espacement à l'intérieur de la sortie attendue correspondra alors à toute séquence de caractères d'espacement à l'intérieur de la sortie réelle. Par défaut, les caractères d'espacement doivent correspondre de façon exacte. L'option
NORMALIZE_WHITESPACE
est particulièrement utile lorsqu'une ligne de sortie attendue est très longue, et que l'on souhaite la répartir sur plusieurs lignes dans le fichier source.
- doctest.ELLIPSIS¶
Lorsque précisé, un marqueur de points de suspension (
...
) dans la sortie attendue peut correspondre à n'importe quelle partie de chaîne de caractères dans la sortie réelle. Ceci inclut les parties qui traversent les frontières de lignes, ainsi que les parties vides de chaînes de caractères ; ainsi, il est préférable d'en faire une utilisation simple. Les usages complexes mènent aux mêmes surprises du type "oups, il y avait trop de correspondances !" que l'utilisation de.*
dans les expressions régulières.
- doctest.IGNORE_EXCEPTION_DETAIL¶
When specified, doctests expecting exceptions pass so long as an exception of the expected type is raised, even if the details (message and fully qualified exception name) don't match.
For example, an example expecting
ValueError: 42
will pass if the actual exception raised isValueError: 3*14
, but will fail if, say, aTypeError
is raised instead. It will also ignore any fully qualified name included before the exception class, which can vary between implementations and versions of Python and the code/libraries in use. Hence, all three of these variations will work with the flag specified:>>> 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
Note that
ELLIPSIS
can also be used to ignore the details of the exception message, but such a test may still fail based on whether the module name is present or matches exactly.Modifié dans la version 3.2: Maintenant,
IGNORE_EXCEPTION_DETAIL
permet aussi d'ignorer toute information liée au module contenant l'exception qui est en train d'être testée.
- doctest.SKIP¶
Lorsque précisé, cesse complètement l'exécution de tous les exemples. Ceci peut être utile dans des contextes où les exemples doctest sont à la fois de la documentation et des cas de tests, et qu'un exemple doit être inclus pour des raisons de documentation, mais ne devrait pas être vérifié. Par exemple, la sortie de l'exemple doit être aléatoire ; ou encore, lorsque l'exemple peut dépendre de ressources inatteignables pour l'exécuteur de test.
L'option SKIP peut aussi être utilisée temporairement afin de commenter des exemples et d'en empêcher l'exécution.
- doctest.COMPARISON_FLAGS¶
Un masque binaire effectuant une composition avec OU de toutes les options de comparaisons ci-dessus.
Le deuxième groupe d'options détermine comment les échecs de tests sont signalés :
- doctest.REPORT_UDIFF¶
Lorsque précisé, les défaillances qui font intervenir des sorties attendues et réelles multi-lignes sont affichées dans une diff unifiée.
- doctest.REPORT_CDIFF¶
Lorsque précisé, les défaillances qui font intervenir des sorties attendues et réelles multi-lignes sont affichées dans une diff de contexte.
- doctest.REPORT_NDIFF¶
Lorsque précisé, les différences sont obtenues grâce à
difflib.Differ
, en utilisant le même algorithme que le populaire utilitairendiff.py
. Ceci est la seule méthode qui puisse faire la différence à l'intérieur des lignes ainsi que parmi les lignes prises conjointement. Par exemple, si une ligne de sortie attendue contient le chiffre1
alors que la sortie réelle contient la lettrel
, une ligne est insérée avec un marqueur caret démarquant les positions de colonnes où il n'y a pas de correspondance.
- doctest.REPORT_ONLY_FIRST_FAILURE¶
Lorsque précisé, le premier exemple défaillant de chaque doctest est affiché, mais la sortie est supprimée pour tous les autres exemples. Ceci empêche doctest de rapporter les exemples adéquats qui échouent du fait d'échecs précédents ; ceci peut aussi cacher des exemples inadéquats qui échouent de façon indépendante au premier échec. Lorsque
REPORT_ONLY_FIRST_FAILURE
est précisé, les exemples restants sont toujours exécutés, et sont toujours comptabilisés dans le nombre total des lignes échouant ; seulement la sortie est omise.
- doctest.FAIL_FAST¶
Lorsque précisé, mettre fin à l'exécution après le premier exemple défaillant et ne pas essayer d'exécuter les exemples restants. Ainsi, le nombre d'échecs rapporté sera au plus un (1). Cette option peut être utile durant le débogage, étant donné que les exemples suivant le premier échec ne produiront aucune sortie de débogage.
La ligne de commande de doctest accepte l'option
-f
comme un raccourci de-o FAIL_FAST
.Ajouté dans la version 3.4.
- doctest.REPORTING_FLAGS¶
Un masque binaire effectuant une composition avec le OU de toutes les options de signalement ci-dessus.
Il y a aussi une façon d'enregistrer des nouveaux noms d'option, quoique ceci n'est pas utile sauf dans le cas où vous devez faire une extension pour le code interne de doctest
par le biais d'une sous-classe :
- doctest.register_optionflag(name)¶
Crée une nouvelle option avec un nom donné, et renvoie la valeur en nombre entier de la nouvelle option. La fonction
register_optionflag()
peut être utilisée lors de la création de sous-classes à partir deOutputChecker
ouDocTestRunner
pour créer de nouvelles options qui sont supportées par vos sous-classes. La fonctionregister_optionflag()
devrait toujours être appelée par l'expression suivante :MY_FLAG = register_optionflag('MY_FLAG')
Instructions¶
Les instructions doctest peuvent être utilisées afin de modifier les options pour un exemple individuel. Les instructions doctest sont des commentaires Python spéciaux suivant le code source d'un exemple :
directive ::= "#" "doctest:"directive_options
directive_options ::=directive_option
(","directive_option
)* directive_option ::=on_or_off
directive_option_name
on_or_off ::= "+" | "-" directive_option_name ::= "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...
Les caractères d'espacement ne sont pas permis entre les +
ou les -
et le nom de l'option d'instruction. Le nom de l'option d'instruction peut être n'importe lequel des noms d'options expliqués ci-dessus.
Les instructions d'un exemple doctest modifient le comportement de doctest et ce, seulement pour cet exemple. Utilisez +
pour activer le comportement nommé, ou -
pour le désactiver.
For example, this test passes:
>>> 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]
Without the directive it would fail, both because the actual output doesn't have two blanks before the single-digit list elements, and because the actual output is on a single line. This test also passes, and also requires a directive to do so:
>>> print(list(range(20))) # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]
Multiple directives can be used on a single physical line, separated by commas:
>>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
If multiple directive comments are used for a single example, then they are combined:
>>> print(list(range(20))) # doctest: +ELLIPSIS
... # doctest: +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
As the previous example shows, you can add ...
lines to your example
containing only directives. This can be useful when an example is too long for
a directive to comfortably fit on the same line:
>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]
Prendre note que puisque toutes les options sont désactivées par défaut, et comme les instructions s'appliquent uniquement aux exemples dans lesquelles elles apparaissent, activer les options (par le biais de +
dans une instruction) est habituellement le seul choix ayant du sens. Toutefois, les options peuvent aussi être passées aux fonctions qui exécutent les doctests, définissant de nouvelles valeurs par défaut. Dans de tels cas, désactiver une option par l'utilisation de -
dans une instruction peut être utile.
Avertissements¶
Le module doctest
est rigoureux pour ce qui est d'inclure des correspondances exactes dans la sortie attendue. Si un seul caractère ne correspond pas, le test échoue. Ceci vous surprendra probablement quelques fois, alors que vous apprenez exactement ce que Python garantit et ne garantit pas pour qui est des sorties. Par exemple, lorsqu'on affiche un ensemble (set), Python ne garantit pas que les éléments sont affichés dans un ordre particulier ; ainsi un test tel que
>>> foo()
{"spam", "eggs"}
est vulnérable ! Une alternative est de faire
>>> foo() == {"spam", "eggs"}
True
à la place. Une autre façon de faire est
>>> d = sorted(foo())
>>> d
['eggs', 'spam']
Il y en a d'autres, mais vous saisissez l'idée.
Another bad idea is to print things that embed an object address, like
>>> 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>
The ELLIPSIS
directive gives a nice approach for the last example:
>>> C() # doctest: +ELLIPSIS
<C object at 0x...>
Les nombres à virgule flottante sont aussi sujets à de petites variations à la sortie, tout dépendamment de la plateforme utilisée, étant donné que Python s'en remet à la bibliothèque de la plateforme C pour la mise-en-forme des floats, et les bibliothèques C varient grandement pour ce qui de leur qualité sur ce point.
>>> 1./7 # risky
0.14285714285714285
>>> print(1./7) # safer
0.142857142857
>>> print(round(1./7, 6)) # much safer
0.142857
Numbers of the form I/2.**J
are safe across all platforms, and I often
contrive doctest examples to produce numbers of that form:
>>> 3./4 # utterly safe
0.75
Les fractions simples sont aussi plus faciles à comprendre, et cela fait une meilleure documentation.
API de base¶
Les fonctions testmod()
et testfile()
fournissent une interface simple pour doctest qui est suffisante pour les cas d'usage les plus élémentaires. Pour une introduction moins formelle à ces deux fonctions, voir les sections Utilisation simple : vérifier des exemples dans des docstrings et Utilisation simple : vérifier des exemples dans un fichier texte.
- 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)¶
Tous les arguments sauf filename sont optionnels, et doivent être précisés sous forme lettrée.
Teste les exemples dans le fichier nommé filename. Renvoie
(failure_count, test_count)
.L'argument optionnel module_relative précise comment le nom de fichier doit être interprété :
Si module_relative prend la valeur
True
(la valeur par défaut), alors filename précise un chemin relatif au module qui soit indépendant du système d'exploitation (OS). Par défaut, ce chemin est relatif au répertoire du module appelant ; mais si l'argument package est précisé, alors il est relatif à ce paquet. Pour garantir l'indépendance quant au système d'exploitation, filename doit utiliser des caractères/
pour séparer chaque segment de chemin, et ne peut pas être un chemin absolu (c'est-à-dire qu'il ne peut pas commencer par/
).Si module_relative prend la valeur
False
, alors filename précise un chemin en fonction du système d'exploitation. Le chemin peut être absolu ou relatif ; les chemins relatifs sont résolus en rapport au répertoire actif.
L'option name désigne le nom du test ; par défaut, ou si
None
est passé en argument,os.path.basename(filename)
est utilisé.L'option package est un paquet Python ou le nom d'un paquet Python dont le répertoire doit être utilisé comme le répertoire principal pour un nom de fichier lié à un module. Si aucun paquet n'est spécifié, le répertoire du module appelé à l'exécution est utilisé comme le répertoire principal pour les noms de fichiers liés au module. C'est une erreur que de spécifier package si module_relative a
False
comme valeur.L'option globs spécifie un dict à utiliser comme globals lorsque des exemples sont exécutés. Une copie superficielle de ce dict est créée pour le doctest ; ainsi, ces exemples commencent avec un état vide. Par défaut, ou si
None
est passé en argument, un nouveau dict vide est utilisé.L'option extraglobs spécifie un dict intégré dans les variables globales utilisées pour exécuter l'exemple. Ceci fonctionne comme
dict.update()
: si globs et extraglobs ont une clé commune, la valeur associée à extraglobs apparaît dans le dict combiné. Par défaut, ou siNone
est passé en argument, aucune variable globale supplémentaire est utilisée. Ceci est une fonctionnalité avancée qui permet la configuration des doctests. Par exemple, un doctest peut être rédigé pour une classe de base, en utilisant un nom générique pour la classe, puis réutilisé afin de tester un nombre indéfini de sous-classes en passant un dict extraglobs reliant le nom générique à la sous-classe qui doit être testée.L'option verbose affiche une grande quantité d'information si elle est vraie, et affiche uniquement les défaillances si elle est fausse ; par défaut, ou si
None
, celle-ci est vraie si et seulement si-v
est présent danssys.argv
.L'option report affiche un résumé à la fin lorsque vraie ; sinon, rien n'est affiché à la fin. En mode verbose, le résumé est détaillé, sinon le résumé est très bref (en fait, vide si tous les tests ont réussi).
L'option optionflags (dont la valeur par défaut est de zéro) calcule la valeur bitwise OR des options de ligne de commande. Voir la section Options de ligne de commande.
L'option raise_on_error est fausse par défaut. Si elle est vraie, une exception est levée à la première défaillance ou à la première exception qui ne soit prévue dans l'exemple. Ceci permet aux défaillances d'être analysées lors d'un post-mortem. Le comportement par défaut est de poursuivre l'exécution des exemples.
L'option parser définit une classe ou une sous-classe
DocTestParser
qui doit être utilisée pour extraire les tests des fichiers. Par défaut, on utilise un analyseur normal (c'est-à-dire,DocTestParser()
).L'option encoding définit un encodage à utiliser pour convertir le fichier en format unicode.
- doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)¶
Toutes les options sont facultatives, et toutes sauf m doivent être définies en format lettré.
Ceci teste les exemples en docstrings dans les fonctions et les classes accessibles depuis le module m (ou depuis le module
__main__
si m n'a pas été défini ou estNone
), en commençant parm.__doc__
.Also test examples reachable from dict
m.__test__
, if it exists.m.__test__
maps names (strings) to functions, classes and strings; function and class docstrings are searched for examples; strings are searched directly, as if they were docstrings.Seulement les docstrings attribuées à des objets appartenant au module m sont fouillées.
Renvoie
(failure_count, test_count)
.L'option name donne le nom du module ; par défaut, ou si
None
,m.__name__
est utilisé.Optional argument exclude_empty defaults to false. If true, objects for which no doctests are found are excluded from consideration. The default is a backward compatibility hack, so that code still using
doctest.master.summarize
in conjunction withtestmod()
continues to get output for objects with no tests. The exclude_empty argument to the newerDocTestFinder
constructor defaults to true.Les options extraglobs, verbose, report, optionflags, raise_on_error, et globs sont les mêmes que pour la fonction
testfile()
ci-dessus, sauf pour globs, qui estm.__dict__
par défaut.
- doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)¶
Les exemples de test associés à l'objet f ; par exemple, f peut être une chaîne de caractères, un module, une fonction, ou un objet de classe.
Une copie superficielle de l'argument-dictionnaire globs est utilisée pour le contexte d'exécution.
L'option name est utilisée pour les messages d'échec, et prend
"NoName"
comme valeur par défaut.Si l'option verbose est vraie, les sorties sont générées même s'il n'y a aucun échec. Par défaut, la sortie est générée seulement si un exemple échoue.
L'option compileflags donne l'ensemble des options qui doit être utilisée par le compilateur Python lorsqu'il exécute les exemples. Par défaut, ou si
None
, les options sont inférées à partir de l'ensemble des fonctionnalités futures trouvées dans globs.L'option optionflags fonctionne similairement à la fonction
testfile()
ci-dessus.
API de tests unitaires¶
As your collection of doctest'ed modules grows, you'll want a way to run all
their doctests systematically. doctest
provides two functions that can
be used to create unittest
test suites from modules and text files
containing doctests. To integrate with unittest
test discovery, include
a load_tests function in your test module:
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
Il y a deux fonctions principales pour créer des instances de la classe unittest.TestSuite
à partir de fichiers textes et de modules ayant des doctests :
- doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)¶
Convertit des tests doctest à partir d'un ou plusieurs fichiers vers une classe
unittest.TestSuite
.The returned
unittest.TestSuite
is to be run by the unittest framework and runs the interactive examples in each file. If an example in any file fails, then the synthesized unit test fails, and afailureException
exception is raised showing the name of the file containing the test and a (sometimes approximate) line number. If all the examples in a file are skipped, then the synthesized unit test is also marked as skipped.Passe un ou plusieurs chemins (sous forme de chaînes de caractères) à des fichiers textes afin d'être vérifiés.
Les options peuvent être fournies comme des options lettrées :
L'option module_relative précise comment les noms de fichiers dans paths doivent être interprétés :
Si module_relative a
True
comme valeur (valeur par défaut), alors chaque nom de fichier dans paths précise un chemin relatif au module qui soit indépendant du système d'exploitation. Par défaut, ce chemin est relatif au répertoire du module appelant ; mais si l'option package est précisée, alors il est relatif à ce paquet. Afin de garantir l'indépendance face au système d'exploitation, chaque nom de fichier doit utiliser des caractères/
afin de séparer les segments de chemin, et ne peut pas être un chemin absolu (c'est-à-dire, il ne peut pas commencer par/
).Si module_relative prend la valeur
False
, alors filename précise un chemin en fonction du système d'exploitation. Le chemin peut être absolu ou relatif ; les chemins relatifs sont résolus en rapport au répertoire actif.
L'option package est un paquet Python ou le nom d'un paquet Python dont le répertoire dont être utilisé comme le répertoire principal pour un nom de fichier dans paths qui soit lié à un module. Si aucun paquet n'est spécifié, le répertoire du module appelé à l'exécution est utilisé comme le répertoire principal pour les noms de fichiers liés au module. C'est une erreur que de spécifier package si module_relative a
False
comme valeur.L'option setUp précise une fonction de mise-en-place pour la suite de tests. Ceci est appelé avant l'exécution des tests dans chaque fichier. La fonction setUp est passée à un objet
DocTest
. La fonction setUp peut accéder aux valeurs globales du test par le biais de l'attribut globs du test passé.L'option tearDown précise une fonction de démolition pour la suite de tests. Celle-ci est appelée après avoir exécuté les tests dans chaque fichier. La fonction tearDown est passée à un objet
DocTest
. La fonction setUp peut accéder aux valeurs globales du test par l'attribut globs du test passé.L'option globs est un dictionnaire contenant les variables globales initiales pour les tests. Une nouvelle copie de ce dictionnaire est créée pour chaque test. Par défaut, globs est un nouveau dictionnaire vide.
Les options optionflags précisent les options par défaut de doctest pour les tests, créées en composant par un OU les différentes options individuelles. Voir la section Options de ligne de commande. Voir la fonction
set_unittest_reportflags()
ci-dessous pour une meilleure façon de préciser des options de rapport.L'option parser définit une classe ou une sous-classe
DocTestParser
qui doit être utilisée pour extraire les tests des fichiers. Par défaut, on utilise un analyseur normal (c'est-à-dire,DocTestParser()
).L'option encoding définit un encodage à utiliser pour convertir le fichier en format unicode.
La valeur globale
__file__
est ajoutée aux valeurs globales fournies par les doctests, ceux-ci étant téléchargés d'un fichier texte utilisant la fonctionDocFileSuite()
.
- doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, optionflags=0, checker=None)¶
Convertit les tests doctest pour un module donné à une classe
unittest.TestSuite
.The returned
unittest.TestSuite
is to be run by the unittest framework and runs each doctest in the module. If any of the doctests fail, then the synthesized unit test fails, and afailureException
exception is raised showing the name of the file containing the test and a (sometimes approximate) line number. If all the examples in a docstring are skipped, then the synthesized unit test is also marked as skipped.L'option module fournit le module qui sera testé. Il peut prendre la forme d'un objet-module ou celle du nom d'un module (possiblement dotted). Si non-précisée, le module appelant cette fonction est utilisé.
L'option globs est un dictionnaire contenant les variables globales initiales pour les tests. Une nouvelle copie de ce dictionnaire est créée pour chaque test. Par défaut, globs est un nouveau dictionnaire vide.
L'option extraglobs précise un ensemble supplémentaire de variables globales, à fusionner avec globs. Par défaut, aucune variable globale supplémentaire est utilisée.
L'option test_finder est l'instance de
DocTestFinder
(ou un remplacement drop-in) qui est utilisée pour extraire les doctests à partir du module.Les options setUp, tearDown et optionflags sont les mêmes que pour la fonction
DocFileSuite()
ci-dessus.Cette fonction utilise la même technique de recherche que
testmod()
.Modifié dans la version 3.5: La fonction
DocTestSuite()
renvoie une instance vide de la classeunittest.TestSuite
si module ne contient aucune docstring, et ce, au lieu de lever l'exceptionValueError
.
- exception doctest.failureException¶
When doctests which have been converted to unit tests by
DocFileSuite()
orDocTestSuite()
fail, this exception is raised showing the name of the file containing the test and a (sometimes approximate) line number.
Under the covers, DocTestSuite()
creates a unittest.TestSuite
out
of doctest.DocTestCase
instances, and DocTestCase
is a
subclass of unittest.TestCase
. DocTestCase
isn't documented
here (it's an internal detail), but studying its code can answer questions about
the exact details of unittest
integration.
Similarly, DocFileSuite()
creates a unittest.TestSuite
out of
doctest.DocFileCase
instances, and DocFileCase
is a subclass
of DocTestCase
.
So both ways of creating a unittest.TestSuite
run instances of
DocTestCase
. This is important for a subtle reason: when you run
doctest
functions yourself, you can control the doctest
options in
use directly, by passing option flags to doctest
functions. However, if
you're writing a unittest
framework, unittest
ultimately controls
when and how tests get run. The framework author typically wants to control
doctest
reporting options (perhaps, e.g., specified by command line
options), but there's no way to pass options through unittest
to
doctest
test runners.
Pour cette raison, doctest
implémente le concept d'options de rapport de doctest
qui soit spécifique à unittest
, par le biais de cette fonction :
- doctest.set_unittest_reportflags(flags)¶
Voir les options de ligne de commandes de
doctest
pour l'utilisation.L'argument flags prend la composition OU bit à bit des arguments. Voir la section Options de ligne de commande. Ce sont uniquement les "options de rapport" qui peuvent être utilisées.
This is a module-global setting, and affects all future doctests run by module
unittest
: therunTest()
method ofDocTestCase
looks at the option flags specified for the test case when theDocTestCase
instance was constructed. If no reporting flags were specified (which is the typical and expected case),doctest
'sunittest
reporting flags are bitwise ORed into the option flags, and the option flags so augmented are passed to theDocTestRunner
instance created to run the doctest. If any reporting flags were specified when theDocTestCase
instance was constructed,doctest
'sunittest
reporting flags are ignored.La valeur prise par les options de rapport de
unittest
et ce, avant que la fonction n'ait été appelée, est renvoyée par la fonction.
API avancé¶
The basic API is a simple wrapper that's intended to make doctest easy to use. It is fairly flexible, and should meet most users' needs; however, if you require more fine-grained control over testing, or wish to extend doctest's capabilities, then you should use the advanced API.
The advanced API revolves around two container classes, which are used to store the interactive examples extracted from doctest cases:
Example
: Un unique statement Python, pris conjointement avec sa sortie attendue.DocTest
: Une collection deExample
, habituellement extraits d'une seule docstring ou fichier texte.
Additional processing classes are defined to find, parse, and run, and check doctest examples:
DocTestFinder
: Finds all docstrings in a given module, and uses aDocTestParser
to create aDocTest
from every docstring that contains interactive examples.DocTestParser
: Creates aDocTest
object from a string (such as an object's docstring).DocTestRunner
: Executes the examples in aDocTest
, and uses anOutputChecker
to verify their output.OutputChecker
: Compares the actual output from a doctest example with the expected output, and decides whether they match.
The relationships among these processing classes are summarized in the following diagram:
list of:
+------+ +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+ | ^ +---------+ | ^ (printed)
| | | Example | | |
v | | ... | v |
DocTestParser | Example | OutputChecker
+---------+
Objets doctest¶
- class doctest.DocTest(examples, globs, name, filename, lineno, docstring)¶
A collection of doctest examples that should be run in a single namespace. The constructor arguments are used to initialize the attributes of the same names.
DocTest
définit les attributs suivants. Ils sont initialisés par le constructeur, et ne doivent pas être modifiés directement.- examples¶
A list of
Example
objects encoding the individual interactive Python examples that should be run by this test.
- globs¶
The namespace (aka globals) that the examples should be run in. This is a dictionary mapping names to values. Any changes to the namespace made by the examples (such as binding new variables) will be reflected in
globs
after the test is run.
- name¶
A string name identifying the
DocTest
. Typically, this is the name of the object or file that the test was extracted from.
- filename¶
The name of the file that this
DocTest
was extracted from; orNone
if the filename is unknown, or if theDocTest
was not extracted from a file.
- lineno¶
The line number within
filename
where thisDocTest
begins, orNone
if the line number is unavailable. This line number is zero-based with respect to the beginning of the file.
- docstring¶
The string that the test was extracted from, or
None
if the string is unavailable, or if the test was not extracted from a string.
Exemples d'objets¶
- class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)¶
A single interactive example, consisting of a Python statement and its expected output. The constructor arguments are used to initialize the attributes of the same names.
Example
defines the following attributes. They are initialized by the constructor, and should not be modified directly.- source¶
A string containing the example's source code. This source code consists of a single Python statement, and always ends with a newline; the constructor adds a newline when necessary.
- want¶
The expected output from running the example's source code (either from stdout, or a traceback in case of exception).
want
ends with a newline unless no output is expected, in which case it's an empty string. The constructor adds a newline when necessary.
- exc_msg¶
The exception message generated by the example, if the example is expected to generate an exception; or
None
if it is not expected to generate an exception. This exception message is compared against the return value oftraceback.format_exception_only()
.exc_msg
ends with a newline unless it'sNone
. The constructor adds a newline if needed.
- lineno¶
The line number within the string containing this example where the example begins. This line number is zero-based with respect to the beginning of the containing string.
- indent¶
The example's indentation in the containing string, i.e., the number of space characters that precede the example's first prompt.
- options¶
A dictionary mapping from option flags to
True
orFalse
, which is used to override default options for this example. Any option flags not contained in this dictionary are left at their default value (as specified by theDocTestRunner
's optionflags). By default, no options are set.
Objets DocTestFinder¶
- class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)¶
A processing class used to extract the
DocTest
s that are relevant to a given object, from its docstring and the docstrings of its contained objects.DocTest
s can be extracted from modules, classes, functions, methods, staticmethods, classmethods, and properties.The optional argument verbose can be used to display the objects searched by the finder. It defaults to
False
(no output).The optional argument parser specifies the
DocTestParser
object (or a drop-in replacement) that is used to extract doctests from docstrings.If the optional argument recurse is false, then
DocTestFinder.find()
will only examine the given object, and not any contained objects.If the optional argument exclude_empty is false, then
DocTestFinder.find()
will include tests for objects with empty docstrings.La classe
DocTestFinder
définit la méthode suivante :- find(obj[, name][, module][, globs][, extraglobs])¶
Return a list of the
DocTest
s that are defined by obj's docstring, or by any of its contained objects' docstrings.The optional argument name specifies the object's name; this name will be used to construct names for the returned
DocTest
s. If name is not specified, thenobj.__name__
is used.The optional parameter module is the module that contains the given object. If the module is not specified or is
None
, then the test finder will attempt to automatically determine the correct module. The object's module is used:As a default namespace, if globs is not specified.
To prevent the DocTestFinder from extracting DocTests from objects that are imported from other modules. (Contained objects with modules other than module are ignored.)
Afin de trouver le nom du fichier contenant l'objet.
To help find the line number of the object within its file.
If module is
False
, no attempt to find the module will be made. This is obscure, of use mostly in testing doctest itself: if module isFalse
, or isNone
but cannot be found automatically, then all objects are considered to belong to the (non-existent) module, so all contained objects will (recursively) be searched for doctests.The globals for each
DocTest
is formed by combining globs and extraglobs (bindings in extraglobs override bindings in globs). A new shallow copy of the globals dictionary is created for eachDocTest
. If globs is not specified, then it defaults to the module's __dict__, if specified, or{}
otherwise. If extraglobs is not specified, then it defaults to{}
.
Objets DocTestParser¶
- class doctest.DocTestParser¶
A processing class used to extract interactive examples from a string, and use them to create a
DocTest
object.La classe
DocTestFinder
définit les méthodes suivantes :- get_doctest(string, globs, name, filename, lineno)¶
Extrait tous les exemples de doctests à partir de la chaîne de caractère donnée, et les réunit dans un objet
DocTest
.Notez que globs, name, filname et lineno sont des attributs pour le nouvel objet
DocTest
. Voir la documentation pourDocTest
pour plus d'information.
Objets TestResults¶
Objets DocTestRunner¶
- class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)¶
A processing class used to execute and verify the interactive examples in a
DocTest
.The comparison between expected outputs and actual outputs is done by an
OutputChecker
. This comparison may be customized with a number of option flags; see section Options de ligne de commande for more information. If the option flags are insufficient, then the comparison may also be customized by passing a subclass ofOutputChecker
to the constructor.The test runner's display output can be controlled in two ways. First, an output function can be passed to
run()
; this function will be called with strings that should be displayed. It defaults tosys.stdout.write
. If capturing the output is not sufficient, then the display output can be also customized by subclassing DocTestRunner, and overriding the methodsreport_start()
,report_success()
,report_unexpected_exception()
, andreport_failure()
.The optional keyword argument checker specifies the
OutputChecker
object (or drop-in replacement) that should be used to compare the expected outputs to the actual outputs of doctest examples.The optional keyword argument verbose controls the
DocTestRunner
's verbosity. If verbose isTrue
, then information is printed about each example, as it is run. If verbose isFalse
, then only failures are printed. If verbose is unspecified, orNone
, then verbose output is used iff the command-line switch-v
is used.The optional keyword argument optionflags can be used to control how the test runner compares expected output to actual output, and how it displays failures. For more information, see section Options de ligne de commande.
The test runner accumulates statistics. The aggregated number of attempted, failed and skipped examples is also available via the
tries
,failures
andskips
attributes. Therun()
andsummarize()
methods return aTestResults
instance.La classe
DocTestRunner
définit les méthodes suivantes :- report_start(out, test, example)¶
Report that the test runner is about to process the given example. This method is provided to allow subclasses of
DocTestRunner
to customize their output; it should not be called directly.example is the example about to be processed. test is the test containing example. out is the output function that was passed to
DocTestRunner.run()
.
- report_success(out, test, example, got)¶
Report that the given example ran successfully. This method is provided to allow subclasses of
DocTestRunner
to customize their output; it should not be called directly.example is the example about to be processed. got is the actual output from the example. test is the test containing example. out is the output function that was passed to
DocTestRunner.run()
.
- report_failure(out, test, example, got)¶
Report that the given example failed. This method is provided to allow subclasses of
DocTestRunner
to customize their output; it should not be called directly.example is the example about to be processed. got is the actual output from the example. test is the test containing example. out is the output function that was passed to
DocTestRunner.run()
.
- report_unexpected_exception(out, test, example, exc_info)¶
Report that the given example raised an unexpected exception. This method is provided to allow subclasses of
DocTestRunner
to customize their output; it should not be called directly.example is the example about to be processed. exc_info is a tuple containing information about the unexpected exception (as returned by
sys.exc_info()
). test is the test containing example. out is the output function that was passed toDocTestRunner.run()
.
- run(test, compileflags=None, out=None, clear_globs=True)¶
Run the examples in test (a
DocTest
object), and display the results using the writer function out. Return aTestResults
instance.The examples are run in the namespace
test.globs
. If clear_globs is true (the default), then this namespace will be cleared after the test runs, to help with garbage collection. If you would like to examine the namespace after the test completes, then use clear_globs=False.compileflags gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to globs.
The output of each example is checked using the
DocTestRunner
's output checker, and the results are formatted by theDocTestRunner.report_*()
methods.
- summarize(verbose=None)¶
Print a summary of all the test cases that have been run by this DocTestRunner, and return a
TestResults
instance.The optional verbose argument controls how detailed the summary is. If the verbosity is not specified, then the
DocTestRunner
's verbosity is used.
DocTestParser
définit les attributs suivants :- tries¶
Number of attempted examples.
- failures¶
Number of failed examples.
- skips¶
Number of skipped examples.
Ajouté dans la version 3.13.
Objets OutputChecker¶
- class doctest.OutputChecker¶
A class used to check the whether the actual output from a doctest example matches the expected output.
OutputChecker
defines two methods:check_output()
, which compares a given pair of outputs, and returnsTrue
if they match; andoutput_difference()
, which returns a string describing the differences between two outputs.La classe
OutputChecker
définit les méthodes suivantes :- check_output(want, got, optionflags)¶
Return
True
iff the actual output from an example (got) matches the expected output (want). These strings are always considered to match if they are identical; but depending on what option flags the test runner is using, several non-exact match types are also possible. See section Options de ligne de commande for more information about option flags.
- output_difference(example, got, optionflags)¶
Return a string describing the differences between the expected output for a given example (example) and the actual output (got). optionflags is the set of option flags used to compare want and got.
Débogage¶
Doctest fournit plusieurs mécanismes pour déboguer des exemples doctest :
Plusieurs fonctions convertissent les doctests en programmes Python exécutables, qui peuvent être exécutés grâce au débogueur Python,
pdb
.The
DebugRunner
class is a subclass ofDocTestRunner
that raises an exception for the first failing example, containing information about that example. This information can be used to perform post-mortem debugging on the example.The
unittest
cases generated byDocTestSuite()
support thedebug()
method defined byunittest.TestCase
.You can add a call to
pdb.set_trace()
in a doctest example, and you'll drop into the Python debugger when that line is executed. Then you can inspect current values of variables, and so on. For example, supposea.py
contains just this module docstring:""" >>> def f(x): ... g(x*2) >>> def g(x): ... print(x+3) ... import pdb; pdb.set_trace() >>> f(3) 9 """
Alors une séance interactive de Python peut ressembler à ceci :
>>> 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) >>>
Functions that convert doctests to Python code, and possibly run the synthesized code under the debugger:
- doctest.script_from_examples(s)¶
Convertit du texte contenant des exemples en un script.
Argument s is a string containing doctest examples. The string is converted to a Python script, where doctest examples in s are converted to regular code, and everything else is converted to Python comments. The generated script is returned as a string. For example,
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 """))
affiche:
# Set x and y to 1 and 2. x, y = 1, 2 # # Print their sum: print(x+y) # Expected: ## 3
Cette fonction est utilisée à l'interne par d'autres fonctions (voir ci-bas), mais peut aussi être utile lorsque l'on souhaite transformer une séance interactive de Python en script Python.
- doctest.testsource(module, name)¶
Convertit en script l'objet doctest.
Argument module is a module object, or dotted name of a module, containing the object whose doctests are of interest. Argument name is the name (within the module) of the object with the doctests of interest. The result is a string, containing the object's docstring converted to a Python script, as described for
script_from_examples()
above. For example, if modulea.py
contains a top-level functionf()
, thenimport a, doctest print(doctest.testsource(a, "a.f"))
prints a script version of function
f()
's docstring, with doctests converted to code, and the rest placed in comments.
- doctest.debug(module, name, pm=False)¶
Débogue les doctests pour un objet.
The module and name arguments are the same as for function
testsource()
above. The synthesized Python script for the named object's docstring is written to a temporary file, and then that file is run under the control of the Python debugger,pdb
.Une copie superficielle de
module.__dict__
est utilisée à la fois pour les contextes d'exécution locaux et globaux.Optional argument pm controls whether post-mortem debugging is used. If pm has a true value, the script file is run directly, and the debugger gets involved only if the script terminates via raising an unhandled exception. If it does, then post-mortem debugging is invoked, via
pdb.post_mortem()
, passing the traceback object from the unhandled exception. If pm is not specified, or is false, the script is run under the debugger from the start, via passing an appropriateexec()
call topdb.run()
.
- doctest.debug_src(src, pm=False, globs=None)¶
Débogue les doctests dans une chaîne de caractères.
Ceci est similaire à la fonction
debug()
décrite ci-haut, mis-à-part qu'une chaîne de caractères contenant des exemples doctest est définie directement, par l'option src.L'option pm a la même définition que dans la fonction
debug()
ci-haut.L'option globs définit un dictionnaire à utiliser comme contexte d'exécution global et local. Si elle n'est pas définie, ou si
None
, un dictionnaire vide est utilisé. Si définie, une copie superficielle du dictionnaire est utilisée.
The DebugRunner
class, and the special exceptions it may raise, are of
most interest to testing framework authors, and will only be sketched here. See
the source code, and especially DebugRunner
's docstring (which is a
doctest!) for more details:
- class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)¶
A subclass of
DocTestRunner
that raises an exception as soon as a failure is encountered. If an unexpected exception occurs, anUnexpectedException
exception is raised, containing the test, the example, and the original exception. If the output doesn't match, then aDocTestFailure
exception is raised, containing the test, the example, and the actual output.Pour de l'information sur les paramètres et méthodes du constructeur, voir la documentation pour la classe
DocTestrunner
dans la section API avancé.
Il y a deux exceptions qui peuvent être levées par des instances DebugRunner
:
- exception doctest.DocTestFailure(test, example, got)¶
Une exception levée par
DocTestRunner
pour signaler que la sortie obtenue suite à un exemple doctest ne correspond pas à la sortie attendue. Les arguments du constructeur sont utilisés pour initialiser les attributs des mêmes noms.
DocTestFailure
définit les attributs suivants :
- DocTestFailure.test¶
L'objet issu de la classe
DocTest
qui était en cours d'exécution lorsque l'exemple a échoué.
- DocTestFailure.got¶
La sortie obtenue par l'exécution de l'exemple.
- exception doctest.UnexpectedException(test, example, exc_info)¶
Une exception levée par
DocTestRunner
afin de signaler qu'un exemple doctest a levé une exception inattendue. Les arguments du constructeur sont utilisés pour initialiser les attributs des mêmes noms.
UnexpectedException
définit les attributs suivants :
- UnexpectedException.test¶
L'objet issu de la classe
DocTest
qui était en cours d'exécution lorsque l'exemple a échoué.
- UnexpectedException.exc_info¶
Un n-uplet contenant l'information au sujet de l'exception inattendue, telle que retourné par
sys.exc_info()
.
Éditorial¶
Comme mentionné dans l'introduction, doctest
a présentement trois usages principaux :
Vérifier les exemples dans les docstrings.
Test de régression.
De la documentation exécutable / des tests littéraires.
These uses have different requirements, and it is important to distinguish them. In particular, filling your docstrings with obscure test cases makes for bad documentation.
When writing a docstring, choose docstring examples with care. There's an art to
this that needs to be learned---it may not be natural at first. Examples should
add genuine value to the documentation. A good example can often be worth many
words. If done with care, the examples will be invaluable for your users, and
will pay back the time it takes to collect them many times over as the years go
by and things change. I'm still amazed at how often one of my doctest
examples stops working after a "harmless" change.
Doctest also makes an excellent tool for regression testing, especially if you don't skimp on explanatory text. By interleaving prose and examples, it becomes much easier to keep track of what's actually being tested, and why. When a test fails, good prose can make it much easier to figure out what the problem is, and how it should be fixed. It's true that you could write extensive comments in code-based testing, but few programmers do. Many have found that using doctest approaches instead leads to much clearer tests. Perhaps this is simply because doctest makes writing prose a little easier than writing code, while writing comments in code is a little harder. I think it goes deeper than just that: the natural attitude when writing a doctest-based test is that you want to explain the fine points of your software, and illustrate them with examples. This in turn naturally leads to test files that start with the simplest features, and logically progress to complications and edge cases. A coherent narrative is the result, instead of a collection of isolated functions that test isolated bits of functionality seemingly at random. It's a different attitude, and produces different results, blurring the distinction between testing and explaining.
Regression testing is best confined to dedicated objects or files. There are several options for organizing tests:
Write text files containing test cases as interactive examples, and test the files using
testfile()
orDocFileSuite()
. This is recommended, although is easiest to do for new projects, designed from the start to use doctest.Define functions named
_regrtest_topic
that consist of single docstrings, containing test cases for the named topics. These functions can be included in the same file as the module, or separated out into a separate test file.Define a
__test__
dictionary mapping from regression test topics to docstrings containing test cases.
Lorsque vous placez vos tests dans un module, le module lui-même peut être l'exécuteur de tests. Lorsqu'un test échoue, vous pouvez signifier à votre exécuteur de tests de rouler une seconde fois uniquement les tests qui échouent et ce, tant que vous travaillez sur le problème. Voici un exemple minimal d'un test exécuteur de tests :
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")
Notes