Formation Python
Le cadre de test doctest est un module Python fourni avec Python. Cet article explique comment mettre des doctests dans votre code et en dehors de celui-ci dans un fichier séparé. Ensuite, je montrerai comment je l’utilise pour tester markdown.py.
modèle conceptuel de python doctest
C'est de python.org:
Le module doctest recherche des morceaux de texte qui ressemblent à des sessions interactives Python,
et exécute ensuite ces sessions pour vérifier qu'elles fonctionnent exactement comme indiqué. …
J'aime penser à doctest comme si je suis assis à une invite interactive python et que je tape des choses. Le doctest est un script qui dit: «Ma session devrait ressembler à ceci. Si ce n’est pas le cas, quelque chose ne va pas.
En fait, je pense que certaines personnes l'utilisent de cette façon. Ils écrivent un module, puis montrent comment cela fonctionne dans un shell interactif, puis copient / collent la session dans une docstring en tant que doctests.
Toutefois, cela ne fonctionne pas très bien dans TDD, où le code ne fonctionne pas avant d’écrire le test. Avec TDD, je dois vraiment penser au résultat exact de quelque chose avant Ça marche.
Lorsque vous utilisez doctest et TDD, cela peut finir par devenir assez itératif:
- Écrire des doctests
- Exécuter les doctests pour voir qu'ils échouent
- Écrivez un code qui devrait le faire passer
- S'il échoue toujours, examinez l'échec.
- Si c'est un faux échec, et que le doctest est juste trop pointilleux, alors modifiez le doctest, éventuellement
avec les drapeaux doctest, puis aller à 2. - S'il s'agit d'un véritable échec, corrigez le code, puis passez à l'étape 2.
J'ai trouvé que certains des aspects les plus épineux de doctest peuvent être minimisés avec l'utilisation d'un adaptateur api. J'utiliserai un adaptateur dans l'exemple markdown.py de ce post.
exemple de doctest
Voici un module simple avec une fonction, avec deux doctests intégrés dans la docstring.
inut_math.py:
'' '
Module montrant comment les doctests peuvent être inclus avec le code source
Chaque ligne '>>>' est exécutée comme dans un shell python et compte comme un test.
La ligne suivante, sinon '>>>' est la sortie attendue de la ligne précédente.
Si quelque chose ne correspond pas exactement (y compris les espaces de fin), le test échoue.
'' '
def multiplier (a, b):
"" "
>>> multiplier (4, 3)
12
>>> multiplier ('a', 3)
'aaa'
"" "
retourne a * b
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 |
''' Module montrant comment les doctests peuvent être inclus avec le code source Chaque '>>>La ligne 'est exécutée comme dans un shell python et compte comme un test. La prochaine ligne, sinon '>>>'est la sortie attendue de la ligne précédente. Si quelque chose ne 't rencontre exactement (comprenant traînant les espaces), la tester échoue. ''' def multiplier (a, b): "" " >>> multiplier (4, 3) 12 >>> multiplier ('une', 3) 'aaa' """ revenir une * b |
courir doctest
Vous exécutez doctest comme ceci:
> python -m doctest
ou
> python -m doctest -v
> python –m doctest <fichier> ou > python –m doctest –v <fichier> |
Le «-v» signifie prolixe. Verbose est très utile pour tester vos doctests, puisque doctest n’affiche rien si tous les tests sont réussis.
> python -m doctest inutile_math.py
> python -m doctest -v inutile_math.py
En essayant:
multiplier (4, 3)
Attendant:
12
D'accord
En essayant:
multiplier ('a', 3)
Attendant:
'aaa'
D'accord
1 items n'avaient pas de test:
inut_math
1 items ont passé tous les tests:
2 tests en inutile_math.multiplier
2 tests en 2 items.
2 ont réussi et 0 a échoué.
Test réussi.
>
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 |
> python –m doctest inut_math.py > python –m doctest –v inut_math.py En essayant: multiplier(4, 3) Attendant: 12 D'accord En essayant: multiplier('une', 3) Attendant: 'aaa' D'accord 1 articles eu non tests: inutile_math 1 articles passé tout tests: 2 tests dans inut_math.multiplier 2 tests dans 2 articles. 2 passé et 0 échoué. Tester passé. > |
Vous pouvez voir lors de la première utilisation que rien ne s'imprime, car tous les tests réussissent.
doctests dans un fichier séparé du code
Une des fonctionnalités vraiment intéressantes de doctest est la possibilité de mettre vos doctests dans un fichier texte. Ceci est particulièrement utile pour les tests fonctionnels, car cela vous permet d'utiliser doctest pour tester même les interfaces non-python.
Pour notre exemple mathématique simple, je peux simplement mettre le même code de la docstring dans un fichier texte.
test_unnecessary_math.txt:
Ceci est une suite de régression basée sur doctest pour inutile_math.py
Chaque ligne '>>' est exécutée comme dans un shell python et compte comme un test.
Si ce n'est pas le cas, la ligne suivante est la sortie attendue de la ligne précédente.
Si quelque chose ne correspond pas exactement (y compris les espaces de fin), le test échoue.
>>> à partir d'importation inutile_math multiplier
>>> multiplier (3, 4)
12
>>> multiplier ('a', 3)
'aaa'
Ce est une doctest basé régression suite pour inut_math.py Chaque '>>' ligne est courir comme si dans une python coquille, et compte comme une tester. le suivant ligne, si ne pas '>>' est la attendu sortie de la précédent ligne. Si n'importe quoi nene correspond pas exactement (y compris les espaces de fin), le test échoue. >>> à partir d'importation inutile_math multiplier >>> multiplier (3, 4) 12 >>> multiplier ('une', 3) 'aaa' |
exécuter des doctests dans un fichier séparé
Exécuter doctest sur un fichier revient à l’exécuter sur un module.
> python -m doctest test_unnecessary_math.txt
> python -m doctest -v test_unnecessary_math.txt
En essayant:
de nécessité_math importer multiplier
Ne rien attendre
D'accord
En essayant:
multiplier (3, 4)
Attendant:
12
D'accord
En essayant:
multiplier ('a', 3)
Attendant:
'aaa'
D'accord
1 items ont passé tous les tests:
3 tests dans test_unnecessary_math.txt
3 tests en 1 items.
3 réussis et 0 échoué.
Test réussi.
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 |
> python –m doctest test_unnecessary_math.SMS > python –m doctest –v test_unnecessary_math.SMS En essayant: de inut_math importation multiplier Attendant rien D'accord En essayant: multiplier(3, 4) Attendant: 12 D'accord En essayant: multiplier('une', 3) Attendant: 'aaa' D'accord 1 articles passé tout tests: 3 tests dans test_unnecessary_math.SMS 3 tests dans 1 articles. 3 passé et 0 échoué. Tester passé. |
exemple avec markdown.py
Pour markdown.py, je ne veux pas inclure de doctests dans le code. Étant donné que je teste uniquement l’interface CLI externe (via un adaptateur), j’utiliserai la méthode ‘doctests in a text file’.
Je ne vais pas écrire tout de suite des tests pour la syntaxe complète. Mes trois premiers tests porteront sur les paragraphes, les balises astérisques simples et les balises fortes à double astérisque.
test_markdown_doctest.txt:
Pour exécuter: python -m doctest test_markdown_doctest.txt
ou: python -m doctest -v test_markdown_doctest.txt
>>> depuis markdown_adapter import run_markdown
>>> run_markdown ('enveloppement de paragraphe')
'
emballage de paragraphe
'
>>> run_markdown ('* em tags *')
'
em tags
'
>>> run_markdown ('** tags forts **')
'
étiquettes fortes
'
À courir: python –m doctest test_markdown_doctest.SMS ou: python –m doctest –v test_markdown_doctest.SMS >>> de markdown_adapter importation run_markdown >>> run_markdown('emballage de paragraphe') ' emballage de paragraphe ' >>> run_markdown('* em tags *') ' em tags ' >>> run_markdown('** étiquettes fortes **') ' étiquettes fortes ' |
Eh bien, c’est assez simple. J’ai importé ‘run_markdown’ depuis mon adaptateur api. Ensuite, je jette quelques exemples de chaînes dans le script et montre ce que je compte voir apparaître.
test markdown.py
Voici le résultat de l'exécution de doctest sur mon fichier texte.
> python -m doctest test_markdown_doctest.txt
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 6, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('enveloppement de paragraphe')
Attendu:
'
emballage de paragraphe
'
Eu:
'emballage de paragraphe'
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 9, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('* em tags *')
Attendu:
'
em tags
'
Eu:
'* em tags *'
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 12, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('** tags forts **')
Attendu:
'
étiquettes fortes
'
Eu:
'** étiquettes fortes **'
************************************************* *********************
1 articles ont échoué:
3 sur 4 dans test_markdown_doctest.txt
*** Échec du test *** 3 échecs.
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
> python –m doctest test_markdown_doctest.SMS ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 6, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('emballage de paragraphe') Attendu: ' emballage de paragraphe ' Eu: 'emballage de paragraphe' ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 9, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('* em tags *') Attendu: ' em tags ' Eu: '* em tags *' ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 12, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('** étiquettes fortes **') Attendu: ' étiquettes fortes ' Eu: '** étiquettes fortes **' ********************************************************************** 1 articles eu les échecs: 3 de 4 dans test_markdown_doctest.SMS ***Tester Échoué*** 3 les échecs. |
Et avec verbeux.
> python -m doctest -v test_markdown_doctest.txt
En essayant:
depuis markdown_adapter import run_markdown
Ne rien attendre
D'accord
En essayant:
run_markdown ('enveloppement de paragraphe')
Attendant:
'
emballage de paragraphe
'
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 6, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('enveloppement de paragraphe')
Attendu:
'
emballage de paragraphe
'
Eu:
'emballage de paragraphe'
En essayant:
run_markdown ('* em tags *')
Attendant:
'
em tags
'
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 9, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('* em tags *')
Attendu:
'
em tags
'
Eu:
'* em tags *'
En essayant:
run_markdown ('** tags forts **')
Attendant:
'
étiquettes fortes
'
************************************************* *********************
Fichier "test_markdown_doctest.txt", ligne 12, dans test_markdown_doctest.txt
Exemple d'échec:
run_markdown ('** tags forts **')
Attendu:
'
étiquettes fortes
'
Eu:
'** étiquettes fortes **'
************************************************* *********************
1 articles ont échoué:
3 sur 4 dans test_markdown_doctest.txt
4 tests en 1 items.
1 réussi et 3 échoué.
*** Échec du test *** 3 échecs.
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
> python –m doctest –v test_markdown_doctest.SMS En essayant: de markdown_adapter importation run_markdown Attendant rien D'accord En essayant: run_markdown('emballage de paragraphe') Attendant: ' emballage de paragraphe ' ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 6, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('emballage de paragraphe') Attendu: ' emballage de paragraphe ' Eu: 'emballage de paragraphe' En essayant: run_markdown('* em tags *') Attendant: ' em tags ' ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 9, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('* em tags *') Attendu: ' em tags ' Eu: '* em tags *' En essayant: run_markdown('** étiquettes fortes **') Attendant: ' étiquettes fortes ' ********************************************************************** Fichier "test_markdown_doctest.txt", ligne 12, dans test_markdown_doctest.SMS Échoué Exemple: run_markdown('** étiquettes fortes **') Attendu: ' étiquettes fortes ' Eu: '** étiquettes fortes **' ********************************************************************** 1 articles eu les échecs: 3 de 4 dans test_markdown_doctest.SMS 4 tests dans 1 articles. 1 passé et 3 échoué. ***Tester Échoué*** 3 les échecs. |
Comme vous pouvez le voir. Une fois que vous êtes convaincu que vos tests sont corrects, le paramètre de verbose n’ajoute pas grand chose. Vous obtiendrez de nombreuses sorties sans commentaires s'il y a des erreurs.
Dans mon cas, tout a échoué !!! Mais c’est bien, car je n’ai encore rien mis en place, j’ai juste un bout.
plus d'infos doctest
Tous les exemples de ce message sont disponibles dans le projet github markdown.py. L’exemple mathématique se trouve dans un dossier appelé ‘simple_doctest_example’.
Le site python.org contient de très bonnes informations sur l’utilisation de doctest.
Sur cette même page, vous trouverez une explication sur l’utilisation des fichiers texte pour vos doctests.
Doug Hellmann a un excellent article sur le doctest que je recommande vivement. Il s’appelle Tester par la documentation et couvre de nombreux problèmes que vous pouvez rencontrer, notamment le traitement de plusieurs lignes, espaces, sorties imprévisibles, etc.
Je traiterai de certains de ces aspects au fur et à mesure de la mise en œuvre et des tests de markdown.py.
suivant
Ensuite, j’essaierai d’implémenter les mêmes tests en utilisant unittest, parfois appelé PyUnit.
[ad_2]