Formation Python
J'aimerais terminer cette récente série d'articles sur les appareils Pytest en présentant ma version d'une sorte de référence.
Comme ce message est un peu long, voici quelques liens vers le contenu enfoui ici.
Puisque je prévois d’utiliser cette référence pour ma propre référence, je vais ajouter quelques liens ici, en haut, à des éléments qui me semblent utiles en ce qui concerne les appareils les plus fiables.
Et… pendant que je lance des liens, voici les autres articles de la série:
J'essaie de garder les exemples dans ce post genre de petite-ish.
Cependant, je risque d'être trop concis. (ou trop verbeux).
Il est également possible que l’ordre que j’ai énoncé soit étrange. J'ai fait beaucoup de copier / coller à partir de l'éditeur de code et de la fenêtre bash pour mettre ce message en ligne.
S'il vous plaît, faites-moi savoir:
- si j’ai perdu un copier / coller et qu’il ya quelque chose de bizarre ici.
- si j’ai été trop concis ou incertain.
- si ce que je dis est complètement faux. Surtout celui-ci
- si vous avez réellement atteint la fin sans vouloir vouloir me jeter quelque chose.
Note sur le code commun
Pour tous les exemples, le fichier de test que j’exécute a ceci en haut:
depuis __future__ import print_function
importation de pytest
de __futur__ importation fonction_impression importation pytest |
Cependant, je ne vais pas le copier dans tous les blocs de code ci-dessous.
Je lance également chaque exemple avec:
Exemple d'os nus
Voici un appareil super basique et quelques tests l’utilisant.
@ pytest.fixture ()
def avant ():
print (' navant chaque test')
def test_1 (avant):
print ('test_1 ()')
def test_2 (avant):
print ('test_2 ()')
@pytest.fixation() def avant(): impression(' navant chaque test') def test_1(avant): impression('test_1 ()') def test_2(avant): impression('test_2 ()') |
Avec les paramètres par défaut de ‘pytest.fixture ()’, l’appareil va être appelé pour chaque test nommant cet appareil dans sa liste de paramètres.
Sortie:
avant chaque test
test_1 ()
.
avant chaque test
test_2 ()
.
avant chaque tester test_1() . avant chaque tester test_2() . |
Trois façons d'utiliser un appareil
- nomme le du test.
Juste comme le top exemple - décorateur de fixations
Vous pouvez marquer un test ou une classe de tests avec ‘pytest.mark.usefixtures () 'et inclure une liste des fixtures à utiliser avec le test ou la classe de tests.
Ceci est particulièrement pratique pour les classes de test.
Il est également utile, lors de la conversion de classes unittest, d’utiliser des appareils pytest.
Je vais donner un exemple sous peu. - autouse
Puissant, mais éventuellement dangereux.
Couvert dans la section suivante.
Exemple d'utilisation
Voici un exemple rapide du décorateur.
Le premier exemple peut être écrit comme ceci:
@ pytest.mark.usefixtures ("avant")
def test_1 ():
print ('test_1 ()')
@ pytest.mark.usefixtures ("avant")
def test_2 ():
print ('test_2 ()')
@pytest.marque.utilités("avant") def test_1(): impression('test_1 ()') @pytest.marque.utilités("avant") def test_2(): impression('test_2 ()') |
Ou ca:
test de classe:
@ pytest.mark.usefixtures ("avant")
def test_1 (auto):
print ('test_1 ()')
@ pytest.mark.usefixtures ("avant")
def test_2 (auto):
print ('test_2 ()')
classe Tester: @pytest.marque.utilités("avant") def test_1(soi): impression('test_1 ()') @pytest.marque.utilités("avant") def test_2(soi): impression('test_2 ()') |
Ou ca:
@ pytest.mark.usefixtures ("avant")
test de classe:
def test_1 (auto):
print ('test_1 ()')
def test_2 (auto):
print ('test_2 ()')
@pytest.marque.utilités("avant") classe Tester: def test_1(soi): impression('test_1 ()') def test_2(soi): impression('test_2 ()') |
Tous avec le même effet.
Caractéristiques du luminaire
Si j’indique les paramètres par défaut de ‘pytest.fixture ()’ et j’ajoute un paramètre de requête à mon appareil, cela ressemble à ceci, mais son exécution n’est pas différente.
@ pytest.fixture (scope = 'fonction', params = None, autouse = False)
def avant (demande):
print (' nbefore ()')
retourner Aucun
@pytest.fixation(portée='une fonction', params=Aucun, autouse=Faux) def avant(demande): impression(' nbefore ()') revenir Aucun |
Voyons maintenant ces caractéristiques.
Valeur de retour
Dans cet exemple, l’appareil renvoie «Aucun».
C’est parce que c’est juste un code que je veux exécuter avant mon test, à l’instar des fonctions d’installation traditionnelles, qu’il s’agisse de nez ou de plus léger.
Cependant, vous pouvez renvoyer tout ce que vous voulez à partir de la fonction fixture.
Si votre appareil configure certaines données, lit un fichier ou ouvre une connexion à une base de données, l'accès à ces données ou ressources est ce que vous devez retourner à partir de l'appareil.
Renvoyer des données d'un fixture.
@ pytest.fixture ()
def some_data ():
data = 'foo': 1, 'bar': 2, 'baz': 3
renvoyer des données
def test_foo (some_data):
affirmer des données[‘foo’] == 1
@pytest.fixation() def quelques données(): Les données = 'foo':1, 'bar':2, 'baz':3 revenir Les données def test_foo(quelques données): affirmer quelques données[[[['foo'] == 1 |
Renvoyer un objet de base de données:
@ pytest.fixture ()
def cheese_db (demande):
print (' n[setup] cheese_db, connectez-vous à db ')
# code pour se connecter à votre base de données
a_dictionary_for_now = 'Brie': 'Non', 'Camenbert': 'Ah! Nous avons Camenbert, yessir. '
def fin ():
print (' n[teardown] cheese_db finalizer, déconnecter de db ')
request.addfinalizer (fin)
retourner a_dictionary_for_now
def test_cheese_database (cheese_db):
print ('dans test_cheese_database ()')
pour la variété dans cheese_db.keys ():
print ('% s:% s'% (variété, cheese_db[variety]))
def test_brie (cheese_db):
print ('in test_brie ()')
affirmer cheese_db[‘Brie’] == 'Non'
def test_camenbert (cheese_db):
print ('in test_camenbert ()')
affirmer cheese_db[‘Camenbert’] ! = 'Non'
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 |
@pytest.fixation() def cheese_db(demande): impression(' n[setup] cheese_db, connectez-vous à la base de données ') # code pour se connecter à votre base de données a_dictionary_for_now = 'Brie': 'Non.', Camenbert: 'Ah! Nous avons Camenbert, yessir. def ailette(): impression(' n[teardown] cheese_db finalizer, déconnecter de la base de données ') demande.additif final(ailette) revenir a_dictionary_for_now def base de données test_cheese(cheese_db): impression('dans test_cheese_database ()') pour variété dans cheese_db.clés(): impression('% s:% s' % (variété, cheese_db[[[[variété])) def test_brie(cheese_db): impression('dans test_brie ()') affirmer cheese_db[[[['Brie'] == 'Non.' def test_camenbert(cheese_db): impression('in test_camenbert ()') affirmer cheese_db[[[[Camenbert] ! = 'Non.' |
Finalizer est démontage
Dans l’exemple de code précédent, l’appareil ‘cheese_db’ a ce bit de code:
def cheese_db (demande):
…
def fin ():
print (' n[teardown] cheese_db finalizer, déconnecter de db ')
request.addfinalizer (fin)
…
def cheese_db(demande): ... def ailette(): impression(' n[teardown] cheese_db finalizer, déconnecter de la base de données ') demande.additif final(ailette) ... |
La fonction «fin» agit comme le «démontage» de l’appareil.
Le nom n’a rien de spécial.
Vous pouvez le nommer "démolition", "cheese_db_teardown" ou "quelquechose_else".
Ce n'est pas grave.
Le finaliseur est appelé après tous les tests utilisant le gabarit.
Si vous avez utilisé des fixtures paramétrées, le finaliseur est appelé entre les instances des changements de fixtures paramétrées.
Portée
Scope contrôle combien de fois un appareil est appelé. La valeur par défaut est "function".
Voici les options pour la portée:
une fonction | Exécuter une fois par test |
classe | Exécuter une fois par classe de tests |
module | Exécuter une fois par module |
session | Exécuter une fois par session |
Puisque la portée par défaut est "function", l'exemple de base de données cheese ouvrira et fermera la base de données pour chaque test.
[setup] cheese_db, connectez-vous à la base de données
dans test_brie ()
.
[teardown] cheese_db finalizer, déconnecter de la base de données
[setup] cheese_db, connectez-vous à la base de données
dans test_camenbert ()
.
[teardown] cheese_db finalizer, déconnecter de la base de données
[[[[installer] cheese_db, relier à db dans base de données test_cheese() Camenbert : Ah! nous avoir Camenbert, Oui monsieur. Brie : Non. . [[[[abattre] cheese_db finaliseur, déconnecter de db [[[[installer] cheese_db, relier à db dans test_brie() . [[[[abattre] cheese_db finaliseur, déconnecter de db [[[[installer] cheese_db, relier à db dans test_camenbert() . [[[[abattre] cheese_db finaliseur, déconnecter de db |
Cela n’a pas vraiment de sens. Surtout si la connexion est une opération fastidieuse.
Changer la portée:
@ pytest.fixture (scope = "module")
def cheese_db (demande):
…
@pytest.fixation(portée="module") def cheese_db(demande): ... |
Et répétons-le:
[[[[installer] cheese_db, relier à db dans base de données test_cheese() Camenbert : Ah! nous avoir Camenbert, Oui monsieur. Brie : Non. .dans test_brie() .dans test_camenbert() . [[[[abattre] cheese_db finaliseur, déconnecter de db |
C'est mieux.
Demande d'objets
Dans l'exemple de fromage db, l'appareil contient un paramètre de requête. Vous avez besoin du paramètre request à un appareil pour ajouter un finaliseur.
Cependant, il a également d'autres utilisations.
Dans l’exemple ci-dessous, je montre l’utilisation (et bien, l’impression) de certains éléments. Voir API pytest pour une liste complète.
@ pytest.fixture ()
def my_fixture (demande):
print (' n —————–')
print ('nom_fichier:% s'% request.fixturename)
print ('portée:% s'% request.scope)
print ('function:% s'% request.function .__ name__)
print ('cls:% s'% request.cls)
print ('module:% s'% request.module .__ name__)
print ('fspath:% s'% request.fspath)
impression('—————–')
si request.function .__ name__ == 'test_three':
request.applymarker (pytest.mark.xfail)
def test_one (mon_fixture):
print ('test_one ():')
Classe TestClass ():
def test_two (self, my_fixture):
print ('test_two ()')
def test_three (mon_fixture):
print ('test_three ()')
affirmer Faux
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@pytest.fixation() def mon_fixture(demande): impression(' n —————–') impression('fixturename:% s' % demande.nom du luminaire) impression('scope:% s' % demande.portée) impression('les fonctions' % demande.une fonction.__prénom__) impression('cls:% s' % demande.cls) impression('modules' % demande.module.__prénom__) impression('fspath:% s' % demande.fspath) impression('—————–') si demande.une fonction.__prénom__ == 'test_three': demande.appliquer le marqueur(pytest.marque.xfail) def test_one(mon_fixture): impression('test_one ():') classe TestClass(): def test_two(soi, mon_fixture): impression('test_two ()') def test_trois(mon_fixture): impression('test_three ()') affirmer Faux |
Paramètres
Un paramètre facultatif pour le décorateur de luminaires est ‘params’.
La valeur par défaut est «Aucun».
Pour chaque valeur dans params, le fixture sera appelé avec request.param renseigné avec cette valeur.
Les tests utilisant cet appareil seront appelés une fois pour chaque valeur dans params.
Exemple de jouet
Un exemple est en ordre ici.
Ce premier exemple est stupide, mais montre les mécanismes, l’utilité de l’indicateur -v et la mesure dans laquelle py.test gère les échecs des tests paramétrés.
@ pytest.fixture (params =[1,2,3] )
def test_data (demande):
return request.param
def test_not_2 (test_data):
print ('test_data:% s'% test_data)
assert test_data! = 2
@pytest.fixation( params=[[[[1,2,3] ) def données de test(demande): revenir demande.param def test_not_2(données de test): impression('test_data:% s' % données de test) affirmer données de test ! = 2 |
Cela doit exécuter ‘test_not_2’ trois fois et échouer lorsque 2 est transmis.
Je vais le lancer sans et avec le drapeau -v
> py.test test_params.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2
collectionné 3 articles
test_params.py .F.
================================= FAILURES ============== =====================
________________________________ test_not_2[2] ________________________________
test_data = 2
def test_not_2 (test_data):
print ('test_data:% s'% test_data)
> assert test_data! = 2
E affirmer 2! = 2
test_params.py:10: AssertionError
——————————- Capturé stdout —————– ————–
test_data: 2
===================== 1 a échoué, 2 ont passé en 0,02 seconde ==================== =
> py.test -v test_params.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2 – C: Python27 python2.7.exe
collecter … collectionné 3 articles
test_params.py:8: test_not_2[1] PASSÉ
test_params.py:8: test_not_2[2] ÉCHOUÉ
test_params.py:8: test_not_2[3] PASSÉ
================================= FAILURES ============== =====================
________________________________ test_not_2[2] ________________________________
test_data = 2
def test_not_2 (test_data):
print ('test_data:% s'% test_data)
> assert test_data! = 2
E affirmer 2! = 2
test_params.py:10: AssertionError
——————————- Capturé stdout —————– ————–
test_data: 2
===================== 1 a échoué, 2 ont passé en 0,02 seconde ==================== =
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 |
> py.tester test_params.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 3 articles test_params.py .F. ================================== LES ÉCHECS =================================== ________________________________ test_not_2[[[[2] ________________________________ données de test = 2 def test_not_2(données de test): impression('test_data:% s' % données de test) > affirmer données de test ! = 2 E affirmer 2 ! = 2 test_params.py:dix: AssertionError –––––––––––––––– Capturé stdout –––––––––––––––– données de test: 2 ===================== 1 échoué, 2 passé dans 0,02 secondes ====================== > py.tester –v test_params.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 – C:Python27python2.7.exe la collecte ... collecté 3 articles test_params.py:8: test_not_2[[[[1] PASSÉ test_params.py:8: test_not_2[[[[2] ÉCHOUÉ test_params.py:8: test_not_2[[[[3] PASSÉ ================================== LES ÉCHECS =================================== ________________________________ test_not_2[[[[2] ________________________________ données de test = 2 def test_not_2(données de test): impression('test_data:% s' % données de test) > affirmer données de test ! = 2 E affirmer 2 ! = 2 test_params.py:dix: AssertionError –––––––––––––––– Capturé stdout –––––––––––––––– données de test: 2 ===================== 1 échoué, 2 passé dans 0,02 secondes ====================== |
Exemple réel
Passons maintenant à une utilisation plus réelle du paramétrage, de l’entrée et de la sortie attendue dans le monde réel.
Voici une réécriture du test de démarques à partir du post d’introduction de pytest.
La fonction ‘run_markdown’ est un adaptateur d’API logicielle, qui prend en charge l’appel du script de démarquage sur la ligne de commande.
depuis markdown_adapter import run_markdown
@ pytest.fixture (params =[
# tuple avec (input, attendOutput)
('texte normal', 'texte normal
'),
('* em tags *', '
em tags
'),
('** étiquettes fortes **', '
étiquettes fortes
')
])
def test_data (demande):
retour request.param
def test_markdown (test_data):
(the_input, the_expected_output) = test_data
the_output = run_markdown (the_input)
print (' ntest_markdown ():')
print ('input:% s'% the_input)
print ('output:% s'% the_output)
print ('attendu:% s'% the_expected_output)
assert the_output == the_expected_output
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 |
de markdown_adapter importation courir_réduction @pytest.fixation( params=[[[[ # tuple avec (input, attendOutput) ('texte normal' , 'texte normal '), ('* em tags *' , ' em tags '), ('** étiquettes fortes **', ' étiquettes fortes ') ]) def données de test(demande): revenir demande.param def test_markdown(données de test): (l'entrée, the_expected_output) = données de test le résultat = run_markdown(l'entrée) impression(' ntest_markdown ():') impression(' contributions' % l'entrée) impression(' les sorties' % le résultat) impression('Attendu:% s' % the_expected_output) affirmer le résultat == the_expected_output |
La sortie indique clairement que le test «test_markdown» est appelé 3 fois.
Bien entendu, les déclarations imprimées sont inutiles.
Je les ai laissés à des fins de démonstration.
> py.test -s test_markdown.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2
collectionné 3 articles
test_markdown.py
test_markdown ():
entrée: texte normal
sortie: texte normal
attendu: texte normal
.
test_markdown ():
entrée: * em tags *
sortie: em tags
attendu: em tags
.
test_markdown ():
entrée: ** balises fortes **
sortie: étiquettes fortes
attendu: étiquettes fortes
.
========================== 3 passés en 0,11 secondes =================== ========
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 |
> py.tester –s test_markdown.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 3 articles test_markdown.py test_markdown(): contribution : régulier texte sortie : régulier texte attendu: régulier texte . test_markdown(): contribution : *em Mots clés* sortie : <em>em Mots clés</em> attendu: <em>em Mots clés</em> . test_markdown(): contribution : **fort Mots clés** sortie : <fort>fort Mots clés</fort> attendu: <fort>fort Mots clés</fort> . ========================== 3 passé dans 0,11 secondes =========================== |
Normalement, vous n'avez pas besoin des déclarations imprimées pour voir ce qui se passe.
Je vais extraire les instructions d’impression et modifier la chaîne "attendue" de la dernière valeur en entrée pour montrer comment py.test est très utile pour signaler le jeu de données qui a échoué.
@ pytest.fixture (params =[
# tuple avec (input, attendOutput)
('texte normal', 'texte normal
'),
('* em tags *', '
em tags
'),
('** étiquettes fortes **', '
étiquettes fortes
')
])
def test_data (demande):
retour request.param
def test_markdown (test_data):
(the_input, the_expected_output) = test_data
the_output = run_markdown (the_input)
assert the_output == the_expected_output
@pytest.fixation( params=[[[[ # tuple avec (input, attendOutput) ('texte normal' , 'texte normal '), ('* em tags *' , ' em tags '), ('** étiquettes fortes **', ' étiquettes fortes ') ]) def données de test(demande): revenir demande.param def test_markdown(données de test): (l'entrée, the_expected_output) = données de test le résultat = run_markdown(l'entrée) affirmer le résultat == the_expected_output |
sortie:
> py.test test_markdown2.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2
collectionné 3 articles
test_markdown2.py ..F
================================= FAILURES ============== =====================
__________________________ test_markdown[test_data2] __________________________
test_data = ('** tags forts **', 'étiquettes fortes
')
def test_markdown (test_data):
(the_input, the_expected_output) = test_data
the_output = run_markdown (the_input)
> assert the_output == the_expected_output
E affirmer '
s …
'=='
st … balises
'
E –
étiquettes fortes
E? ^^^^^^
E + étiquettes fortes
E? ^^
test_markdown2.py:17: AssertionError
===================== 1 échec, 2 échoués en 0,11 seconde ===================== =
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
> py.tester test_markdown2.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 3 articles test_markdown2.py ..F ================================== LES ÉCHECS =================================== __________________________ test_markdown[[[[test_data2] __________________________ données de test = ('** étiquettes fortes **', 'étiquettes fortes ') def test_markdown(données de test): (l'entrée, the_expected_output) = données de test le résultat = run_markdown(l'entrée) > affirmer le résultat == the_expected_sortie E affirmer ' s … ' == ' st … balises ' E – <p><fort>fort Mots clés</fort> E ? ^^^^^^ E + <fort>fort Mots clés</em> E ? ^^ test_markdown2.py:17: AssertionError ===================== 1 échoué, 2 passé dans 0,11 secondes ====================== |
Autouse
Le paramètre facultatif du décorateur de luminaires est ‘autouse’.
La valeur par défaut est "False".
Avec la valeur ‘False’, les tests qui souhaitent utiliser le projecteur doivent soit le nommer dans leur liste de paramètres, soit faire l’objet d’un décorateur d’appareils.
Reportez-vous aux deux premiers éléments de la section «Trois façons d’utiliser un appareil» pour plus d’informations.
Avec la valeur définie sur "True", tous les tests de cette session utilisent simplement le projecteur automatiquement.
Oui, un grand pouvoir entraîne de grandes responsabilités.
Alors utilisez-le avec précaution.
Cependant, il est très pratique dans les endroits où vous auriez utilisé le style xunit setup_module
Pour notre exemple, disons simplement que j’ai un code de rapport que je voudrais utiliser en haut du module et en haut d’une fonction de test.
Les tests eux-mêmes n’ont pas besoin d’être manipulés, car ils ne renvoient aucune donnée.
@ pytest.fixture (scope = "module", autouse = True)
def mod_header (demande):
print (' n —————–')
print ('utilisateur:% s'% getpass.getuser ())
print ('module:% s'% request.module .__ name__)
impression('—————–')
@ pytest.fixture (scope = "function", autouse = True)
def func_header (demande):
print (' n —————–')
print ('function:% s'% request.function .__ name__)
print ('time:% s'% time.asctime ())
impression('—————–')
def test_one ():
print ('dans test_one ()')
def test_two ():
print ('dans test_two ()')
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 |
@pytest.fixation(portée="module", autouse=Vrai) def mod_header(demande): impression(' n —————–') impression('utilisateurs' % passer.getuser()) impression('modules' % demande.module.__prénom__) impression('—————–') @pytest.fixation(portée="une fonction", autouse=Vrai) def func_header(demande): impression(' n —————–') impression('les fonctions' % demande.une fonction.__prénom__) impression('temps:% s' % temps.Asctime()) impression('—————–') def test_one(): impression('dans test_one ()') def test_two(): impression('dans test_two ()') |
sortie:
> py.test -s test_autouse.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2
collectionné 2 articles
test_autouse.py
—————–
utilisateur: okken
module: test_autouse
—————–
—————–
fonction: test_one
heure: Mar Fév 04 17:31:20 2014
—————–
dans test_one ()
.
—————–
fonction: test_two
heure: Mar Fév 04 17:31:20 2014
—————–
dans test_two ()
.
========================== 2 passés en 0.02 secondes =================== ========
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 |
> py.tester –s test_autouse.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 2 articles test_autouse.py ––––––––– utilisateur : okken module : test_autouse ––––––––– ––––––––– une fonction : test_one temps : Mar fév 04 17:31:20 2014 ––––––––– dans test_one() . ––––––––– une fonction : test_two temps : Mar fév 04 17:31:20 2014 ––––––––– dans test_two() . ========================== 2 passé dans 0,02 secondes =========================== |
Plusieurs appareils
Dans les exemples que j'ai utilisés jusqu'à présent, seuls les tests utilisent au maximum un appareil nommé.
Vous pouvez utiliser plus.
Exemple simple:
@ pytest.fixture (scope = "module")
def foo (demande):
print (' nfoo setup – module fixture')
def fin ():
print ('foo teardown – module fixture')
request.addfinalizer (fin)
@ pytest.fixture ()
barre de défilement (demande):
print ('bar setup – function fixture')
def fin ():
print ('démontage de la barre – fonction' '
request.addfinalizer (fin)
@ pytest.fixture ()
def baz (demande):
print ('baz setup – function fixture')
def fin ():
print ('baz teardown – function fixture')
request.addfinalizer (fin)
def test_one (foo, bar, baz):
print ('dans test_one ()')
def test_two (foo, bar, baz):
print ('dans test_two ()')
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 |
@pytest.fixation(portée="module") def foo(demande): impression(' nfoo setup – module fixture') def ailette(): impression('foo démontage – montage du module') demande.additif final(ailette) @pytest.fixation() def bar(demande): impression('configuration du bar – fonction') def ailette(): impression('démontage de la barre – fonction') demande.additif final(ailette) @pytest.fixation() def baz(demande): impression('baz setup – fonction fixture') def ailette(): impression('baz démontage – fonction fixture') demande.additif final(ailette) def test_one(foo, bar, baz): impression('dans test_one ()') def test_two(foo, bar, baz): impression('dans test_two ()') |
sortie:
> py.test -s test_multiple.py
============================== La session de test commence ================= ===========
plate-forme win32 – Python 2.7.2 – pytest-2.4.2
collectionné 2 articles
test_multiple.py
foo setup – montage de module
configuration du bar – fonction fixture
baz setup – fonction fixture
dans test_one ()
.baz démontage – fonction fixture
démontage de la barre – fonction fixture
configuration du bar – appareil fonctionnel
baz setup – fonction fixture
dans test_two ()
.baz démontage – fonction fixture
démontage de la barre – fonction fixture
foo démontage – montage du module
========================== 2 passés en 0.01 secondes =================== ========
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 |
> py.tester –s test_multiple.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 2 articles test_multiple.py foo installer – module fixation bar installer – une fonction fixation baz installer – une fonction fixation dans test_one() .baz abattre – une fonction fixation bar abattre – une fonction fixation bar installer – une fonction fixation baz installer – une fonction fixation dans test_two() .baz abattre – une fonction fixation bar abattre – une fonction fixation foo abattre – module fixation ========================== 2 passé dans 0,01 secondes =========================== |
Modularité: appareils utilisant d'autres appareils
Les tests peuvent utiliser un ou plusieurs appareils.
Les appareils eux-mêmes peuvent également utiliser un ou plusieurs appareils.
Je vais réécrire l’exemple précédent, mais au lieu que les tests incluent tous les appareils foo, bar et baz, je les enchaînerai.
Et une autre ride, "test_two" n'inclura que "bar".
@ pytest.fixture (scope = "module")
def foo (demande):
print (' nfoo setup – module fixture')
def fin ():
print ('foo teardown – module fixture')
request.addfinalizer (fin)
@ pytest.fixture ()
def bar (demande, toto):
print ('bar setup – function fixture')
def fin ():
print ('démontage de la barre – fonction' '
request.addfinalizer (fin)
@ pytest.fixture ()
def baz (demande, barre):
print ('baz setup – function fixture')
def fin ():
print ('baz teardown – function fixture')
request.addfinalizer (fin)
def test_one (baz):
print ('dans test_one ()')
def test_two (bar): # utilisez uniquement la barre
print ('dans test_two ()')
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 |
@pytest.fixation(portée="module") def foo(demande): impression('nfoo setup – module fixture') def ailette(): impression('foo teardown – module fixture') demande.additif final(ailette) @pytest.fixation() def bar(demande, foo): impression('bar setup – function fixture') def ailette(): impression('bar teardown – function fixture') demande.additif final(ailette) @pytest.fixation() def baz(demande, bar): impression('baz setup – function fixture') def ailette(): impression('baz teardown – function fixture') demande.additif final(ailette) def test_one(baz): impression('in test_one()') def test_two(bar): # only use bar impression('in test_two()') |
sortie
> py.test -s test_modular.py
============================= test session starts =============================
platform win32 — Python 2.7.2 — pytest-2.4.2
collectionné 2 articles
test_modular.py
foo setup – module fixture
bar setup – function fixture
baz setup – function fixture
in test_one()
.baz teardown – function fixture
bar teardown – function fixture
bar setup – function fixture
in test_two()
.bar teardown – function fixture
foo teardown – module fixture
========================== 2 passed in 0.02 seconds ===========================
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 |
> py.tester –s test_modular.py ============================= tester session départs ============================= Plate-forme win32 – Python 2.7.2 – pytest–2.4.2 collecté 2 articles test_modular.py foo setup – module fixation bar setup – une fonction fixation baz setup – une fonction fixation dans test_one() .baz teardown – une fonction fixation bar teardown – une fonction fixation bar setup – une fonction fixation dans test_two() .bar teardown – une fonction fixation foo teardown – module fixation ========================== 2 passé dans 0,02 secondes =========================== |
Experimental and still to cover
In this section, I’m listing the caractéristiques expérimentales, and features I haven’t fully tested and/or don’t quite understand yet.
yield_fixture
Thank you Johannes for pointed out this feature in the comments.
You can use ‘yield_fixture’ instead of the ‘fixture’ decorator for functions that yield their value rather than returning them.
The benefits are:
- It works like a context manager.
- You don’t have to register a teardown function via addfinalizer.
- Therfore, you don’t have to include the request parameter just for the addfinalizer function.
Caveats:
It’s still "experimental", so supposedly the syntax/behavior might change in the future.As of pytest 2.7.0, it’s no longer considered experimental. It will stay.- Probably more, but I haven’t used it much to know what else to be careful of.
Here’s a quick example. (Yep. Staight from the comment.)
@pytest.yield_fixture(scope="module")
def cheese_db():
print('n[setup] cheese_db, connect to db')
a_dictionary_for_now = 'Brie': 'No.', 'Camenbert': 'Ah! We have Camenbert, yessir.'
yield a_dictionary_for_now
print('n[teardown] cheese_db finalizer, disconnect from db')
def test_brie(cheese_db):
print('in test_brie()')
assert cheese_db[‘Brie’] == 'No.'
def test_camenbert(cheese_db):
print('in test_camenbert()')
assert cheese_db[‘Camenbert’] != 'No.'
@pytest.yield_fixture(portée="module") def cheese_db(): impression('n[setup] cheese_db, connect to db') a_dictionary_for_now = 'Brie': 'No.', 'Camenbert': 'Ah! We have Camenbert, yessir.' rendement a_dictionary_for_now impression('n[teardown] cheese_db finalizer, disconnect from db') def test_brie(cheese_db): impression('in test_brie()') affirmer cheese_db[[[['Brie'] == 'No.' def test_camenbert(cheese_db): impression('in test_camenbert()') affirmer cheese_db[[[['Camenbert'] != 'No.' |
$ py.test -s pytestfixtures/test_yield.py
====================== test session starts ======================
platform darwin — Python 2.7.5 — py-1.4.20 — pytest-2.5.2
collectionné 2 articles
pytestfixtures/test_yield.py
[setup] cheese_db, connect to db
in test_brie()
.in test_camenbert()
.
[teardown] cheese_db finalizer, disconnect from db
=================== 2 passed in 0.01 seconds ===================
$ py.tester –s pytestfixtures/test_yield.py ====================== tester session départs ====================== Plate-forme Darwin – Python 2.7.5 – py–1.4.20 – pytest–2.5.2 collecté 2 articles pytestfixtures/test_yield.py [[[[setup] cheese_db, relier à db dans test_brie() .dans test_camenbert() . [[[[teardown] cheese_db finalizer, déconnecter de db =================== 2 passé dans 0,01 secondes =================== |
ATTENTION: My recommendation is to be aware of this feature, but use ‘addfinalizer’ for production test code.
This is a cool feature. But since it’s still listed as ‘experimental’, and I haven’t done much testing with it or testing of it, I can’t in good conscience recommend it’s use.
Hey pytest devs: Let me know if this WARNING is too strong.
I DO recommend you use it IFF you are either solo or on a small team where you are able to easily change the test code in the future if the syntax/behavior changes in future pytest releases.
ids
More information at pytest.org
I played around with this a bit, but couldn’t get anything to work.
I’m sure I was just doing something wrong.
If anyone has a working example they could share, please do.
Retour d'information
Leave a comment. Let me know if this is helpful or confusing. If you end up finding some bell or whistle of pytest fixtures that I missed, let me know.
[ad_2]