Test Python efficace avec Pytest – Real Python

By | avril 20, 2020

Python pas cher

Le test de votre code apporte une grande variété d'avantages. Cela augmente votre confiance que le code se comporte comme prévu et garantit que les modifications apportées à votre code ne provoqueront pas de régressions. Écrire et maintenir des tests est un travail difficile, vous devez donc utiliser tous les outils à votre disposition pour le rendre aussi indolore que possible. pytest est l'un des meilleurs outils que vous pouvez utiliser pour augmenter la productivité de vos tests.

Dans ce didacticiel, vous apprendrez:

  • Quelle avantages pytest des offres
  • Comment vous assurer que vos tests sont apatride
  • Comment rendre les tests répétitifs plus compréhensible
  • Comment courir sous-ensembles de tests par nom ou groupes personnalisés
  • Comment créer et maintenir réutilisable test des utilitaires

Comment installer pytest

Pour suivre certains des exemples de ce didacticiel, vous devez installer pytest. Comme avec la plupart des packages Python, vous pouvez installer pytest dans un environnement virtuel de PyPI utilisant pépin:

$ python -m pip installe pytest

le pytest La commande sera désormais disponible dans votre environnement d'installation.

Ce qui rend pytest Si utile?

Si vous avez déjà écrit des tests unitaires pour votre code Python, vous avez peut-être déjà utilisé la fonction intégrée de Python Test de l'unité module. Test de l'unité fournit une base solide sur laquelle construire votre suite de tests, mais elle présente quelques lacunes.

Un certain nombre de cadres de test tiers tentent de résoudre certains des problèmes Test de l'unité, et pytest s'est avéré être l'un des plus populaires. pytest est un écosystème riche en fonctionnalités et basé sur des plugins pour tester votre code Python.

Si vous n'avez pas eu le plaisir d'utiliser pytest encore, alors vous êtes pour un régal! Sa philosophie et ses fonctionnalités rendront votre expérience de test plus productive et plus agréable. Avec pytest, les tâches courantes nécessitent moins de code et les tâches avancées peuvent être réalisées grâce à une variété de commandes et de plug-ins permettant de gagner du temps. Il exécutera même vos tests existants hors de la boîte, y compris ceux écrits avec Test de l'unité.

Comme avec la plupart des frameworks, certains modèles de développement qui ont du sens lorsque vous commencez à utiliser pytest peut commencer à causer des douleurs à mesure que votre suite de tests se développe. Ce tutoriel vous aidera à comprendre certains des outils pytest permet de garder vos tests efficaces et efficients même lorsqu'ils évoluent.

Moins de chaudière

La plupart des tests fonctionnels suivent le modèle Arrange-Act-Assert:

  1. Organiserou définir les conditions du test
  2. Acte en appelant une fonction ou une méthode
  3. Affirmer qu'une certaine condition de fin est vraie

Les frameworks de test se connectent généralement aux assertions de votre test afin qu'ils puissent fournir des informations en cas d'échec d'une assertion. Test de l'unité, par exemple, fournit un certain nombre d'utilitaires d'assertion utiles prêts à l'emploi. Cependant, même un petit ensemble de tests nécessite une bonne quantité de code passe-partout.

Imaginez que vous aimeriez écrire une suite de tests juste pour vous assurer Test de l'unité fonctionne correctement dans votre projet. Vous voudrez peut-être écrire un test qui réussit toujours et un qui échoue toujours:

# test_with_unittest.py

de Test de l'unité importation Cas de test

classe TryTesting(Cas de test):
    def test_always_passes(soi):
        soi.assertTrue(Vrai)

    def test_always_fails(soi):
        soi.assertTrue(Faux)

Vous pouvez ensuite exécuter ces tests à partir de la ligne de commande en utilisant le découvrir option de Test de l'unité:

$ python -m unittest découvrir
F.
================================================== ==========
ÉCHEC: test_always_fails (test_with_unittest.TryTesting)
-------------------------------------------------- ----------
Traceback (dernier appel le plus récent):
        Fichier "/.../test_with_unittest.py", ligne 9, dans test_always_fails
                self.assertTrue (False)
AssertionError: False n'est pas vrai

-------------------------------------------------- ----------
Tests Ran 2 en 0,001s

ÉCHEC (échecs = 1)

Comme prévu, un test a réussi et un a échoué. Vous avez prouvé que Test de l'unité fonctionne, mais regardez ce que vous aviez à faire:

  1. Importez le Cas de test classe de Test de l'unité
  2. Créer TryTesting, une sous-classe de Cas de test
  3. Écrivez une méthode dans TryTesting pour chaque test
  4. Utilisez l'un des self.assert * méthodes de unittest.TestCase faire des affirmations

C'est une quantité importante de code à écrire, et parce que c'est le minimum dont vous avez besoin pour tout test, vous finiriez par écrire le même code encore et encore. pytest simplifie ce flux de travail en vous permettant d’utiliser Python affirmer mot clé directement:

# test_with_pytest.py

def test_always_passes():
    affirmer Vrai

def test_always_fails():
    affirmer Faux

C'est ça. Vous n'avez à gérer aucune importation ni aucune classe. Parce que vous pouvez utiliser le affirmer mot-clé, vous n'avez pas besoin d'apprendre ou de vous souvenir des self.assert * méthodes Test de l'unité, Soit. Si vous pouvez écrire une expression que vous pensez évaluer Vrai, puis pytest va le tester pour vous. Vous pouvez l'exécuter en utilisant le pytest commander:

$ pytest
================== la session de test démarre =============================
plateforme Darwin - Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.0
rootdir: /.../effective-python-testing-with-pytest
collecté 2 articles

test_with_pytest.py .F                                          [100%]

======================== FAILURES ========================== =========
___________________ test_always_fails ______________________________

                def test_always_fails ():
>       affirmer faux
E affirmer faux

test_with_pytest.py:5: AssertionError
============== 1 échec, 1 réussi en 0,07s =========================

pytest présente les résultats du test différemment de Test de l'unité. Le rapport montre:

  1. L'état du système, y compris les versions de Python, pytestet tous les plugins que vous avez installés
  2. le rootdirou le répertoire dans lequel rechercher la configuration et les tests
  3. Le nombre de tests découverts par le coureur

La sortie indique alors l'état de chaque test en utilisant une syntaxe similaire à Test de l'unité:

  • Un point (.) signifie que le test a réussi.
  • Une F signifie que le test a échoué.
  • Une E signifie que le test a déclenché une exception inattendue.

Pour les tests qui échouent, le rapport donne une ventilation détaillée de l'échec. Dans l'exemple ci-dessus, le test a échoué car affirmer faux échoue toujours. Enfin, le rapport donne un rapport d'état global de la suite de tests.

Voici quelques exemples d'assertion plus rapides:

def test_uppercase():
    affirmer "bruits forts".plus haut() == "BRUITS FORTS"

def test_reversed():
    affirmer liste(renversé([[[[1, 2, 3, 4])) == [[[[4, 3, 2, 1]

def test_some_primes():
    affirmer 37 dans 
        num
        pour num dans intervalle(1, 50)
        si num ! = 1 et ne pas tout([[[[num % div == 0 pour div dans intervalle(2, num)])
    

La courbe d'apprentissage pour pytest est moins profond que pour Test de l'unité car vous n'avez pas besoin d'apprendre de nouvelles constructions pour la plupart des tests. De plus, l'utilisation de affirmer, que vous avez peut-être utilisé auparavant dans votre code d'implémentation, rend vos tests plus compréhensibles.

Gestion des états et des dépendances

Vos tests dépendent souvent de données ou de doublons de test pour certains des objets de votre code. Dans Test de l'unité, vous pouvez extraire ces dépendances dans installer() et abattre() afin que chaque test de la classe puisse les utiliser. Mais ce faisant, vous pouvez, par inadvertance, dépendre entièrement le test d'une donnée ou d'un objet particulier implicite.

Au fil du temps, les dépendances implicites peuvent conduire à un enchevêtrement complexe de code que vous devez vous détendre pour donner un sens à vos tests. Les tests devraient vous aider à rendre votre code plus compréhensible. Si les tests eux-mêmes sont difficiles à comprendre, alors vous pourriez avoir des ennuis!

pytest adopte une approche différente. Il vous conduit vers explicite des déclarations de dépendances encore réutilisables grâce à la disponibilité des fixtures. pytest Les fixtures sont des fonctions qui créent des données ou testent des doubles ou initialisent un état du système pour la suite de tests. Tout test qui veut utiliser un appareil doit l'accepter explicitement comme argument, donc les dépendances sont toujours énoncées à l'avance.

Les appareils peuvent également utiliser d'autres appareils, encore une fois en les déclarant explicitement en tant que dépendances. Cela signifie qu'au fil du temps, vos luminaires peuvent devenir encombrants et modulaires. Bien que la possibilité d'insérer des appareils dans d'autres appareils offre une flexibilité énorme, cela peut également rendre la gestion des dépendances plus difficile à mesure que votre suite de tests se développe. Plus loin dans ce didacticiel, vous en apprendrez plus sur les appareils et essayez quelques techniques pour gérer ces défis.

Filtrage de test

Au fur et à mesure que votre suite de tests s'agrandit, vous constaterez peut-être que vous souhaitez exécuter quelques tests sur une fonctionnalité et enregistrer la suite complète pour plus tard. pytest propose plusieurs façons de procéder:

  • Filtrage basé sur le nom: Vous pouvez limiter pytest pour exécuter uniquement les tests dont les noms complets correspondent à une expression particulière. Vous pouvez le faire avec le -k paramètre.
  • Portée du répertoire: Par défaut, pytest exécutera uniquement les tests qui se trouvent dans ou sous le répertoire actuel.
  • Catégorisation des tests: pytest peut inclure ou exclure des tests de catégories particulières que vous définissez. Vous pouvez le faire avec le -m paramètre.

La catégorisation des tests en particulier est un outil subtilement puissant. pytest vous permet de créer Des marques, ou des étiquettes personnalisées, pour tout test que vous aimez. Un test peut avoir plusieurs étiquettes et vous pouvez les utiliser pour un contrôle granulaire sur les tests à exécuter. Plus loin dans ce didacticiel, vous verrez un exemple de pytest Les marques fonctionnent et apprennent à les utiliser dans une grande suite de tests.

Paramétrage de l'essai

Lorsque vous testez des fonctions qui traitent des données ou effectuent des transformations génériques, vous vous retrouvez à écrire de nombreux tests similaires. Ils peuvent différer uniquement par l'entrée ou la sortie du code testé. Cela nécessite la duplication du code de test, ce qui peut parfois masquer le comportement que vous essayez de tester.

Test de l'unité offre un moyen de rassembler plusieurs tests en un seul, mais ils n'apparaissent pas comme des tests individuels dans les rapports de résultats. Si un test échoue et que les autres réussissent, le groupe entier renverra toujours un seul résultat ayant échoué. pytest propose sa propre solution dans laquelle chaque test peut réussir ou échouer indépendamment. Vous verrez comment paramétrer les tests avec pytest plus loin dans ce didacticiel.

Architecture basée sur les plugins

L'une des plus belles fonctionnalités de pytest c'est son ouverture à la personnalisation et aux nouvelles fonctionnalités. Presque chaque élément du programme peut être ouvert et modifié. Par conséquent, pytest les utilisateurs ont développé un riche écosystème de plugins utiles.

Bien que certains pytest les plugins se concentrent sur des frameworks spécifiques comme Django, d'autres sont applicables à la plupart des suites de tests. Vous verrez des détails sur certains plugins spécifiques plus loin dans ce didacticiel.

Appareils: gestion des états et des dépendances

pytest les appareils sont un moyen de fournir des données, des doubles de test ou une configuration d'état à vos tests. Les appareils sont des fonctions qui peuvent renvoyer une large gamme de valeurs. Chaque test qui dépend d'un appareil doit accepter explicitement cet appareil comme argument.

Quand créer des appareils

Imaginez que vous écrivez une fonction, format_data_for_display (), pour traiter les données renvoyées par un point de terminaison API. Les données représentent une liste de personnes, chacune avec un prénom, un nom de famille et un titre d'emploi. La fonction doit générer une liste de chaînes comprenant le nom complet de chaque personne (leur prénom suivi de leur nom de famille), un côlon et leur Titre. Pour tester cela, vous pouvez écrire le code suivant:

def format_data_for_display(gens):
    ...  # Implémentez ceci!

def test_format_data_for_display():
    gens = [[[[
        
            "prénom": "Alfonsa",
            "nom de famille": "Ruiz",
            "Titre": "Ingénieur logiciel senior",
        ,
        
            "prénom": "Sayid",
            "nom de famille": "Khan",
            "Titre": "Gestionnaire de projet",
        ,
    ]

    affirmer format_data_for_display(gens) == [[[[
        "Alfonsa Ruiz: ingénieur logiciel senior",
        "Sayid Khan: chef de projet",
    ]

Supposons maintenant que vous devez écrire une autre fonction pour transformer les données en valeurs séparées par des virgules à utiliser dans Excel. Le test serait terriblement similaire:

def format_data_for_excel(gens):
    ... # Implémentez ceci!

def test_format_data_for_excel():
    gens = [[[[
        
            "prénom": "Alfonsa",
            "nom de famille": "Ruiz",
            "Titre": "Ingénieur logiciel senior",
        ,
        
            "prénom": "Sayid",
            "nom de famille": "Khan",
            "Titre": "Gestionnaire de projet",
        ,
    ]

    affirmer format_data_for_excel(gens) == "" "donné, famille, titre
Alfonsa, Ruiz, ingénieur logiciel principal
Sayid, Khan, chef de projet
"" "

Si vous vous retrouvez en train d'écrire plusieurs tests qui utilisent tous les mêmes données de test sous-jacentes, alors un appareil peut être dans votre avenir. Vous pouvez extraire les données répétées dans une seule fonction décorée de @ pytest.fixture pour indiquer que la fonction est un pytest fixation:

importation pytest

@pytest.fixation
def example_people_data():
    revenir [[[[
        
            "prénom": "Alfonsa",
            "nom de famille": "Ruiz",
            "Titre": "Ingénieur logiciel senior",
        ,
        
            "prénom": "Sayid",
            "nom de famille": "Khan",
            "Titre": "Gestionnaire de projet",
        ,
    ]

Vous pouvez utiliser le luminaire en l'ajoutant comme argument à vos tests. Sa valeur sera la valeur de retour de la fonction fixture:

def test_format_data_for_display(example_people_data):
    affirmer format_data_for_display(example_people_data) == [[[[
        "Alfonsa Ruiz: ingénieur logiciel senior",
        "Sayid Khan: chef de projet",
    ]

def test_format_data_for_excel(example_people_data):
    affirmer format_data_for_excel(example_people_data) == "" "donné, famille, titre
Alfonsa, Ruiz, ingénieur logiciel principal
Sayid, Khan, chef de projet
"" "

Chaque test est désormais notablement plus court mais a toujours un chemin clair vers les données dont il dépend. Assurez-vous de nommer votre appareil quelque chose de spécifique. De cette façon, vous pouvez rapidement déterminer si vous souhaitez l'utiliser lors de l'écriture de nouveaux tests à l'avenir!

Quand éviter les luminaires

Les appareils sont parfaits pour extraire des données ou des objets que vous utilisez à travers plusieurs tests. Ils ne sont pas toujours aussi bons pour les tests qui nécessitent de légères variations dans les données. La litière de votre suite de tests avec des appareils n'est pas meilleure que la litière avec des données ou des objets simples. Cela pourrait même être pire en raison de la couche supplémentaire d'indirection.

Comme pour la plupart des abstractions, il faut un peu de pratique et de réflexion pour trouver le bon niveau d'utilisation du luminaire.

Fixtures à l'échelle

Au fur et à mesure que vous extrayez plus d'appareils de vos tests, vous pouvez constater que certains appareils pourraient bénéficier d'une extraction supplémentaire. Les luminaires sont modulaire, afin qu'ils puissent dépendre d'autres appareils. Vous pouvez constater que les luminaires de deux modules de test distincts partagent une dépendance commune. Que pouvez-vous faire dans ce cas?

Vous pouvez déplacer des appareils des modules de test vers des modules plus généraux liés aux appareils. De cette façon, vous pouvez les réimporter dans tous les modules de test qui en ont besoin. C'est une bonne approche lorsque vous vous retrouvez à utiliser un appareil à plusieurs reprises tout au long de votre projet.

pytest cherche des conftest.py modules dans toute la structure du répertoire. Chaque conftest.py fournit la configuration de l'arborescence des fichiers pytest le trouve dans. Vous pouvez utiliser tous les appareils qui sont définis dans un particulier conftest.py dans le répertoire parent du fichier et dans tous les sous-répertoires. C'est un excellent endroit pour installer vos luminaires les plus utilisés.

Un autre cas d'utilisation intéressant pour les appareils est la protection de l'accès aux ressources. Imaginez que vous avez écrit une suite de tests pour le code qui traite les appels d'API. Vous voulez vous assurer que la suite de tests n'effectue aucun appel réseau réel, même si un test exécute accidentellement le code d'appel réseau réel. pytest fournit un monkeypatch appareil pour remplacer les valeurs et les comportements, que vous pouvez utiliser à bon escient:

# conftest.py

importation pytest
importation demandes

@pytest.fixation(autouse=Vrai)
def disable_network_calls(monkeypatch):
    def stunted_get():
        élever Erreur d'exécution("L'accès au réseau n'est pas autorisé pendant les tests!")
    monkeypatch.setattr(demandes, "avoir", lambda *args, **kwargs: stunted_get())

En plaçant disable_network_calls () dans conftest.py et en ajoutant autouse = True , vous vous assurez que les appels réseau seront désactivés dans chaque test de la suite. Tout test qui exécute l'appel de code requests.get () soulèvera un Erreur d'exécution indiquant qu'un appel réseau inattendu se serait produit.

Marques: catégorisation des tests

Dans toute grande suite de tests, certains des tests seront inévitablement lents. Ils peuvent tester le comportement de délai d'expiration, par exemple, ou ils peuvent exercer une large zone du code. Quelle que soit la raison, ce serait bien d'éviter de courir tout les tests lents lorsque vous essayez d'itérer rapidement sur une nouvelle fonctionnalité.

pytest vous permet de définir des catégories pour vos tests et fournit des options pour inclure ou exclure des catégories lorsque vous exécutez votre suite. Vous pouvez marquer un test avec un certain nombre de catégories.

Le marquage des tests est utile pour classer les tests par sous-système ou dépendances. Si certains de vos tests nécessitent un accès à une base de données, par exemple, vous pouvez créer un @ pytest.mark.database_access marque pour eux.

Lorsque vient le temps d'exécuter vos tests, vous pouvez toujours les exécuter tous par défaut avec le pytest commander. Si vous souhaitez exécuter uniquement les tests qui nécessitent un accès à la base de données, vous pouvez utiliser pytest -m database_access. Pour exécuter tous les tests sauf ceux qui nécessitent un accès à la base de données, vous pouvez utiliser pytest -m "not database_access". Vous pouvez même utiliser un autouse appareil pour limiter l'accès de la base de données aux tests marqués d'un database_access.

Certains plugins développent la fonctionnalité des marques en protégeant l'accès aux ressources. le pytest-django plugin fournit un django_db marque. Tous les tests sans cette marque qui tentent d'accéder à la base de données échoueront. Le premier test qui tente d'accéder à la base de données déclenchera la création de la base de données de test de Django.

L'obligation d'ajouter le django_db mark vous pousse à indiquer explicitement vos dépendances. C'est le pytest la philosophie, après tout! Cela signifie également que vous pouvez exécuter des tests qui ne dépendent pas de la base de données beaucoup plus rapidement, car pytest -m "pas django_db" empêchera le test de déclencher la création de la base de données. Les gains de temps s'accumulent vraiment, surtout si vous êtes diligent pour exécuter vos tests fréquemment.

pytest fournit quelques marques hors de la boîte:

  • sauter saute un test sans condition.
  • skipif saute un test si l'expression qui lui est passée est évaluée à Vrai.
  • xfail indique qu'un test devrait échouer, donc si le test Est-ce que échouer, la suite globale peut toujours entraîner un statut de réussite.
  • paramétrer (notez l'orthographe) crée plusieurs variantes d'un test avec différentes valeurs comme arguments. Vous en saurez bientôt plus sur cette marque.

Vous pouvez voir une liste de toutes les marques pytest connaît en exécutant pytest --marqueurs.

Paramétrage: Combinaison de tests

Vous avez vu plus tôt dans ce didacticiel comment pytest les appareils peuvent être utilisés pour réduire la duplication de code en extrayant les dépendances courantes. Les appareils ne sont pas aussi utiles lorsque vous avez plusieurs tests avec des entrées et des sorties attendues légèrement différentes. Dans ces cas, vous pouvez paramétrer une seule définition de test, et pytest créera pour vous des variantes du test avec les paramètres que vous spécifiez.

Imaginez que vous avez écrit une fonction pour dire si une chaîne est un palindrome. Un premier ensemble de tests pourrait ressembler à ceci:

def test_is_palindrome_empty_string():
    affirmer is_palindrome("")

def test_is_palindrome_single_character():
    affirmer is_palindrome("une")

def test_is_palindrome_mixed_casing():
    affirmer is_palindrome("Bob")

def test_is_palindrome_with_spaces():
    affirmer is_palindrome("Jamais impair ou même")

def test_is_palindrome_with_punctuation():
    affirmer is_palindrome("Les oies voient-elles Dieu?")

def test_is_palindrome_not_palindrome():
    affirmer ne pas is_palindrome("abc")

def test_is_palindrome_not_quite():
    affirmer ne pas is_palindrome("abab")

Tous ces tests, à l'exception des deux derniers, ont la même forme:

def test_is_palindrome_<dans certains situation>():
    affirmer is_palindrome("")

Vous pouvez utiliser @ pytest.mark.parametrize () pour remplir cette forme avec différentes valeurs, ce qui réduit considérablement votre code de test:

@pytest.marque.paramétrer("palindrome", [[[[
    "",
    "une",
    "Bob",
    "Jamais impair ou même",
    "Les oies voient-elles Dieu?",
])
def test_is_palindrome(palindrome):
    affirmer is_palindrome(palindrome)

@pytest.marque.paramétrer("non_palindrome", [[[[
    "abc",
    "abab",
])
def test_is_palindrome_not_palindrome(non_palindrome):
    affirmer ne pas is_palindrome(non_palindrome)

Le premier argument pour parametrize () est une chaîne de noms de paramètres délimitée par des virgules. Le deuxième argument est une liste de tuples ou de valeurs uniques qui représentent la ou les valeurs de paramètre. Vous pouvez pousser votre paramétrage un peu plus loin pour combiner tous vos tests en un seul:

@pytest.marque.paramétrer("peut-être_palindrome, résultat_attendu", [[[[
    ("", Vrai),
    ("une", Vrai),
    ("Bob", Vrai),
    ("Jamais impair ou même", Vrai),
    ("Les oies voient-elles Dieu?", Vrai),
    ("abc", Faux),
    ("abab", Faux),
])
def test_is_palindrome(peut-être_palindrome, résultat attendu):
    affirmer is_palindrome(peut-être_palindrome) == résultat attendu

Même si cela a raccourci votre code, il est important de noter que dans ce cas, cela n'a pas fait grand-chose pour clarifier votre code de test. Utilisez la paramétrisation pour séparer les données de test du comportement de test afin de savoir clairement ce que le test teste!

Rapports sur les durées: lutter contre les tests lents

Chaque fois que vous changez de contexte du code d'implémentation en code de test, vous encourez des frais généraux. Si vos tests sont lents au début, les frais généraux peuvent provoquer des frictions et de la frustration.

Vous avez lu plus tôt l'utilisation des marques pour filtrer les tests lents lorsque vous exécutez votre suite. Si vous souhaitez améliorer la vitesse de vos tests, il est utile de savoir quels tests pourraient offrir les plus grandes améliorations. pytest peut automatiquement enregistrer les durées des tests pour vous et signaler les principaux délinquants.

Utilisez le --durations option à la pytest pour inclure un rapport de durée dans vos résultats de test. --durations attend une valeur entière n et signalera le plus lent n nombre de tests. La sortie suivra les résultats de votre test:

$ pytest --durations=3
3.03s appellent test_code.py::test_request_read_timeout
1.07s appellent test_code.py::test_request_connection_timeout
0,57 s appeler test_code.py::test_database_read
======================== 7 passé en 10.06s ====================== =========

Chaque test qui apparaît dans le rapport des durées est un bon candidat pour accélérer car il prend une quantité supérieure à la moyenne du temps de test total.

Sachez que certains tests peuvent avoir une surcharge de configuration invisible. Vous avez lu plus tôt comment le premier test marqué avec django_db va déclencher la création de la base de données de test Django. le durées Le rapport indique le temps nécessaire à la configuration de la base de données dans le test qui a déclenché la création de la base de données, ce qui peut être trompeur.

Utile pytest Plugins

Vous avez appris quelques précieuses pytest plugins plus tôt dans ce tutoriel. Vous pouvez les explorer plus en détail ci-dessous.

pytest-randomly

pytest-randomly fait quelque chose d'apparemment simple mais avec un effet précieux: il force vos tests à s'exécuter dans un ordre aléatoire. pytest recueille toujours tous les tests qu'il peut trouver avant de les exécuter, donc pytest-randomly mélange cette liste de tests juste avant l'exécution.

C'est un excellent moyen de découvrir des tests qui dépendent de l'exécution dans un ordre spécifique, ce qui signifie qu'ils ont un dépendance avec état sur un autre test. Si vous avez créé votre suite de tests à partir de zéro pytest, alors ce n'est pas très probable. Il est plus probable que cela se produise dans les suites de tests vers lesquelles vous migrez pytest.

Le plugin imprimera une valeur de départ dans la description de la configuration. Vous pouvez utiliser cette valeur pour exécuter les tests dans le même ordre que vous essayez de résoudre le problème.

pytest-cov

Si vous mesurez dans quelle mesure vos tests couvrent votre code d'implémentation, vous utilisez probablement le package de couverture. pytest-cov intègre la couverture, vous pouvez donc exécuter pytest --cov pour voir le rapport de couverture du test.

pytest-django

pytest-django fournit une poignée d'appareils et de marques utiles pour gérer les tests Django. Vous avez vu le django_db marque plus tôt dans ce didacticiel, et rf appareil fournit un accès direct à une instance de Django RequestFactory. le réglages fixture fournit un moyen rapide de définir ou de remplacer les paramètres de Django. C'est un formidable coup de pouce pour la productivité de vos tests Django!

Si vous souhaitez en savoir plus sur l'utilisation de pytest avec Django, puis consultez Comment fournir des montages de test pour les modèles Django dans Pytest.

pytest-bdd

pytest peut être utilisé pour exécuter des tests qui n'entrent pas dans le cadre traditionnel des tests unitaires. Le développement basé sur le comportement (BDD) encourage la rédaction de descriptions en langage clair des actions et des attentes probables de l'utilisateur, que vous pouvez ensuite utiliser pour déterminer s'il convient d'implémenter une fonctionnalité donnée. pytest-bdd vous aide à utiliser Gherkin pour écrire des tests de fonctionnalités pour votre code.

Vous pouvez voir quels autres plugins sont disponibles pour pytest avec cette longue liste de plugins tiers.

Conclusion

pytest offre un ensemble de fonctionnalités de productivité de base pour filtrer et optimiser vos tests ainsi qu'un système de plugin flexible qui étend encore sa valeur. Que vous ayez un énorme héritage Test de l'unité suite ou vous démarrez un nouveau projet à partir de zéro, pytest a quelque chose à vous offrir.

Dans ce didacticiel, vous avez appris à utiliser:

  • Agencements pour gérer les dépendances de test, l'état et les fonctionnalités réutilisables
  • Des marques pour classer les tests et limiter l'accès aux ressources externes
  • Paramétrisation pour réduire le code dupliqué entre les tests
  • Durées pour identifier vos tests les plus lents
  • Plugins pour l'intégration avec d'autres frameworks et outils de test

Installer pytest et essayez-le. Vous serez content de l'avoir fait. Bon test!