Maison >développement back-end >Tutoriel Python >Un guide des tests d'unité Python avec unittest et pytest
Cet article explore l'importance des tests de logiciels et pourquoi vous devriez y faire attention. Nous apprendrons à concevoir des tests unitaires et à rédiger des tests unitaires Python. En particulier, nous explorerons deux des cadres de test unitaires les plus couramment utilisés dans Python: unittest et pytest.
Points clés
Introduction aux tests logiciels
Les tests logiciels sont un processus de vérification du comportement des produits logiciels pour évaluer et vérifier qu'ils sont conformes aux spécifications. Un produit logiciel peut contenir des milliers de lignes de code et des centaines de composants qui fonctionnent ensemble. Si une ligne de code ne fonctionne pas correctement, l'erreur peut se propager et provoquer d'autres erreurs. Par conséquent, pour s'assurer que le programme fonctionne comme prévu, il doit être testé.
Parce que les logiciels modernes peuvent être assez complexes, il existe plusieurs niveaux de tests pour évaluer différents aspects de l'exactitude. Selon le programme de niveau de test de certification ISTQB, il y a quatre niveaux de test de logiciels:
Cet article discutera des tests unitaires, mais avant d'y entrer, je voudrais introduire un principe important dans les tests de logiciels.
Les testsne peuvent prouver que l'existence de défauts, mais ne peuvent pas prouver l'absence de défauts.
- ISTQB SYLLABUS CTFL 2018
En d'autres termes, même si tous les tests que vous exécutez n'affichent aucune échelle, cela ne prouvera pas que votre système logiciel est exempt d'erreurs, ou un autre cas de test ne trouvera aucun défaut dans votre comportement logiciel.
Il s'agit du premier niveau de test, également connu sous le nom de test de composants. Dans cette section, un seul composant logiciel est testé. Selon le langage de programmation, une unité logicielle peut être une classe, une fonction ou une méthode. Par exemple, si vous avez une classe Java appelée opération arithmétique qui contient des méthodes multiples et diviser, les tests unitaires de la classe arithmétique doivent tester le comportement correct des méthodes de multiplication et de division.
Les tests unitaires sont généralement effectués par des testeurs de logiciels. Pour exécuter des tests unitaires, les testeurs (ou développeurs) doivent accéder au code source car le code source lui-même est l'objet testé. Par conséquent, cette méthode de test de logiciel qui teste directement le code source est appelée test de boîte blanche.
Vous vous demandez peut-être pourquoi vous devriez vous soucier des tests de logiciels et si cela en vaut la peine. Dans la section suivante, nous analyserons les motivations derrière le système de logiciel de test.
Le principal avantage des tests de logiciels est qu'il améliore la qualité du logiciel. La qualité des logiciels est cruciale, en particulier dans le monde où le logiciel gère toutes sortes de choses dans nos activités quotidiennes. L'amélioration de la qualité des logiciels est toujours un objectif trop vague. Essayons de mieux illustrer ce que nous appelons la qualité des logiciels. Selon ISO / IEC Standard 9126-1 ISO 9126, la qualité du logiciel comprend les facteurs suivants:
Si vous possédez une entreprise, vous devez soigneusement considérer les activités de test de logiciels car cela affectera votre entreprise. Par exemple, en mai 2022, Tesla a rappelé 130 000 voitures en raison de problèmes avec le système d'infodivertissement du véhicule. Ce problème a ensuite été résolu via une mise à jour logicielle distribuée "dans l'air". Ces échecs ont causé du temps et de l'argent à l'entreprise et ont également causé des problèmes aux clients, car ils n'ont pas pu utiliser leurs voitures pendant un certain temps. Le logiciel de test coûte de l'argent, mais les entreprises peuvent également économiser des millions de supports techniques.
Les tests unitaires se concentrent sur la vérification que le logiciel s'exécute correctement, ce qui signifie vérifier que le mappage entre l'entrée et la sortie est effectué correctement. En tant qu'activité de test de bas niveau, les tests unitaires aident à identifier les erreurs tôt afin qu'ils ne les propagent pas à des niveaux plus élevés du système logiciel.
Les autres avantages des tests unitaires comprennent:
Stratégies de test de conception
Voyons maintenant comment concevoir une stratégie de test.
Avant de commencer à planifier votre stratégie de test, il y a une question importante à répondre. Quelles parties du système logiciel souhaitez-vous tester?
Il s'agit d'un problème clé, car les tests exhaustifs sont impossibles. Par conséquent, vous ne pouvez pas tester toutes les entrées et sorties possibles, mais vous devez prioriser les tests en fonction des risques impliqués.
Un certain nombre de facteurs doivent être pris en compte lors de la définition de la portée du test:
Une fois que vous avez défini la portée du test (spécifiant ce que vous devez tester et ce que vous ne devez pas tester), vous pouvez discuter des fonctionnalités d'un bon test unitaire.
Une étape est manquante avant de plonger dans les tests unitaires dans Python. Comment organisons-nous les tests pour les rendre propres et lisibles? Nous utilisons un modèle appelé préparation, exécution et assertion (AAA).
Le modèle de préparation, d'exécution et d'affirmation (AAA) est une stratégie courante pour écrire et organiser des tests unitaires. Il fonctionne comme suit:
Cette stratégie fournit un moyen propre d'organiser des tests unitaires en séparant toutes les parties principales du test (configuration, exécution et validation). De plus, les tests unitaires sont plus faciles à lire car ils suivent tous la même structure.
Tests unitaires dans Python: unittest ou pytest?
Nous allons maintenant discuter de deux cadres de test unitaires différents dans Python. Ces deux cadres sont unittest et pytest.
La bibliothèque standard Python contient le cadre de test unitaire unittest. Ce cadre est inspiré par JUnit, qui est un cadre de test unitaire en Java.
Comme indiqué dans la documentation officielle, unittest prend en charge plusieurs concepts importants que nous mentionnerons dans cet article:
Unittest a sa propre façon d'écrire des tests. En particulier, nous avons besoin:
Étant donné que Unittest est déjà installé, nous sommes prêts à écrire notre premier test unitaire!
Supposons que nous ayons la classe BankAccount:
<code class="language-python">import unittest class BankAccount: def __init__(self, id): self.id = id self.balance = 0 def withdraw(self, amount): if self.balance >= amount: self.balance -= amount return True return False def deposit(self, amount): self.balance += amount return True</code>
Nous ne pouvons pas retirer de l'argent qui dépasse le montant disponible de la dépôt, alors testons si notre code source gère correctement cette situation.
Dans le même fichier Python, nous pouvons ajouter le code suivant:
<code class="language-python">class TestBankOperations(unittest.TestCase): def test_insufficient_deposit(self): # Arrange a = BankAccount(1) a.deposit(100) # Act outcome = a.withdraw(200) # Assert self.assertFalse(outcome)</code>
Nous créons une classe appelée TestBankOperations qui est une sous-classe de UnitTest.TestCase. De cette façon, nous créons un nouveau cas de test.
Dans cette classe, nous définissons une seule fonction de test dont la méthode commence par le test. Ceci est important car chaque méthode de test doit commencer par le test de mots.
Nous nous attendons à ce que cette méthode de test retourne false, ce qui signifie que l'opération a échoué. Pour affirmer le résultat, nous utilisons une méthode d'affirmation spéciale appelée ASSERTFALSE ().
Nous sommes prêts à effectuer le test. Exécutons cette commande sur la ligne de commande:
<code class="language-bash">python -m unittest example.py</code>
Ici, Exemple.py est le nom du fichier contenant tout le code source. La sortie doit ressembler à ceci:
<code>. ---------------------------------------------------------------------- Ran 1 test in 0.001s OK</code>
Très bien! Cela signifie que notre test a réussi. Voyons maintenant à quoi ressemble la sortie lorsqu'il y a un échec. Nous ajoutons un nouveau test à la classe précédente. Essayons de déposer des montants négatifs, ce qui est certainement impossible. Notre code va-t-il gérer cette situation?
Ceci est notre nouvelle méthode de test:
<code class="language-python"> def test_negative_deposit(self): # Arrange a = BankAccount(1) # Act outcome = a.deposit(-100) # Assert self.assertFalse(outcome)</code>
Nous pouvons utiliser le mode détaillé de UnitTest pour effectuer ce test en utilisant le drapeau -v:
<code class="language-bash">python -m unittest -v example.py</code>
La sortie est différente maintenant:
<code>test_insufficient_deposit (example.TestBankOperations) ... ok test_negative_deposit (example.TestBankOperations) ... FAIL ====================================================================== FAIL: test_negative_deposit (example.TestBankOperations) ---------------------------------------------------------------------- Traceback (most recent call last): File "example.py", line 35, in test_negative_deposit self.assertFalse(outcome) AssertionError: True is not false ---------------------------------------------------------------------- Ran 2 tests in 0.002s FAILED (failures=1)</code>
Dans ce cas, le logo détaillé nous donne plus d'informations. Nous savons que Test_Negative_Deposit échoue. En particulier, AssertionError nous dit que le résultat attendu devrait être faux, mais vrai n'est pas faux, ce qui signifie que la méthode renvoie vrai.
Unittest Framework fournit différentes méthodes d'affirmation en fonction de nos besoins:
Maintenant que nous avons une compréhension de base de la façon d'écrire des tests unitaires à l'aide du framework unittest, jetons un coup d'œil à un autre framework Python appelé PyTest.
Pytest Framework est un framework de test d'unité Python qui a certaines fonctionnalités connexes:
Étant donné que Pytest n'est pas installé par défaut, nous devons d'abord l'installer. Notez que PyTest nécessite Python 3.7.
L'installation de Pytest est très facile. Il vous suffit d'exécuter la commande suivante:
<code class="language-python">import unittest class BankAccount: def __init__(self, id): self.id = id self.balance = 0 def withdraw(self, amount): if self.balance >= amount: self.balance -= amount return True return False def deposit(self, amount): self.balance += amount return True</code>
Vérifiez ensuite que tout est installé correctement en tapant:
<code class="language-python">class TestBankOperations(unittest.TestCase): def test_insufficient_deposit(self): # Arrange a = BankAccount(1) a.deposit(100) # Act outcome = a.withdraw(200) # Assert self.assertFalse(outcome)</code>
La sortie doit ressembler à ceci:
<code class="language-bash">python -m unittest example.py</code>
Très bien! Écrivons le premier test à l'aide de PyTest.
Nous utiliserons la classe BankAccount que nous avons écrite plus tôt et nous testerons la même méthode qu'auparavant. De cette façon, il est plus facile de comparer les efforts nécessaires pour rédiger des tests à l'aide de ces deux cadres.
Pour utiliser PyTest pour les tests, nous avons besoin:
Nous créons donc un fichier nommé test_bank.py et le mettons dans un dossier. C'est à quoi ressemble notre première fonction de test:
<code>. ---------------------------------------------------------------------- Ran 1 test in 0.001s OK</code>
Comme vous l'avez remarqué, le seul changement par rapport à la version unittest est la partie Assert. Ici, nous utilisons la méthode d'affirmation Python normale.
Maintenant, nous pouvons jeter un œil au fichier test_bank.py:
<code class="language-python"> def test_negative_deposit(self): # Arrange a = BankAccount(1) # Act outcome = a.deposit(-100) # Assert self.assertFalse(outcome)</code>
Pour exécuter ce test, ouvrons une invite de commande dans le dossier contenant le fichier test_bank.py. Ensuite, exécutez la commande suivante:
<code class="language-bash">python -m unittest -v example.py</code>
La sortie ressemblera à ceci:
<code>test_insufficient_deposit (example.TestBankOperations) ... ok test_negative_deposit (example.TestBankOperations) ... FAIL ====================================================================== FAIL: test_negative_deposit (example.TestBankOperations) ---------------------------------------------------------------------- Traceback (most recent call last): File "example.py", line 35, in test_negative_deposit self.assertFalse(outcome) AssertionError: True is not false ---------------------------------------------------------------------- Ran 2 tests in 0.002s FAILED (failures=1)</code>
Dans ce cas, nous pouvons voir à quel point il est facile d'écrire et d'exécuter des tests. De plus, nous pouvons voir que nous écrivons moins de code que Unittest. Les résultats du test sont également faciles à comprendre.
Continuons à regarder les tests échoués!
Nous utilisons la deuxième méthode que nous avons écrite auparavant, ce qui est appelé test_negative_deposit. Nous refacteurs la partie affirmer et le résultat est le suivant:
<code class="language-bash">pip install -U pytest</code>
Nous exécutons les tests comme auparavant, qui devraient être la sortie:
<code class="language-bash">pytest --version</code>
En analysant la sortie, nous pouvons lire 2 éléments collectés, ce qui signifie que deux tests ont été effectués. Faites défiler vers le bas et nous pouvons voir une erreur s'est produite lors du test de la méthode Test_Negative_Deposit. En particulier, des erreurs se produisent lors de l'évaluation des affirmations. De plus, le rapport indique également que la valeur de la variable de résultat est vraie, ce qui signifie que la méthode de dépôt contient des erreurs.
Étant donné que PyTest utilise le mot-clé Python Assertion par défaut, nous pouvons comparer toutes les sorties que nous atteignons avec une autre variable qui stocke le résultat attendu. Tout cela ne nécessite aucune méthode d'affirmation spéciale.
Conclusion
Dans cet article, nous présentons les bases des tests logiciels. Nous avons découvert pourquoi les tests de logiciels sont cruciaux et pourquoi chacun devrait tester son code. Nous discutons des tests unitaires et de la façon de concevoir et d'implémenter des tests unitaires simples dans Python.
Nous utilisons deux frameworks Python appelés unittest et pytest. Les deux ont des fonctionnalités utiles, et ils sont deux des cadres les plus couramment utilisés dans les tests d'unité Python.
Enfin, nous voyons deux cas de test de base pour vous donner une idée de la façon d'écrire des tests dans les modèles de préparation, d'exécution et d'affirmation.
J'espère que je vous ai convaincu l'importance des tests de logiciels. Choisissez un cadre, comme unittest ou pytest, et commencez à tester - car l'effort supplémentaire en vaut la peine!
Si vous aimez cet article, vous pouvez également trouver le suivant utile:
FAQ sur Python Unit Testing
Que sont les tests unitaires dans Python? Les tests unitaires dans Python sont une technique de test de logiciels dans laquelle une seule unité ou un composant d'un programme est testée isolée pour s'assurer que chaque unité fonctionne comme prévu.
Pourquoi les tests unitaires sont-ils importants dans le développement de Python? Les tests unitaires aident à garantir l'exactitude des composants individuels dans un programme Python. Il aide à détecter tôt les erreurs, fournit un filet sûr pour les modifications de code et prend en charge la maintenabilité du code.
Comment écrire des tests unitaires dans Python? Les tests unitaires dans Python sont souvent écrits à l'aide du module unittest intégré. Vous créez des classes de test héritées à partir des méthodes de test unittest.testcase et d'écriture dans ces classes. Les méthodes de test commencent généralement par "test".
Quels autres frameworks puis-je utiliser pour les tests d'unité Python en plus d'Unittest? Oui, en plus d'Unittest, il existe d'autres cadres de test Python populaires tels que PyTest et Nose2. Ces cadres offrent différentes fonctionnalités et syntaxes, permettant aux développeurs de choisir celui qui répond le mieux à leurs besoins.
Quel est le rôle du luminaire dans les tests unitaires Python? Le luminaire est un moyen de définir des conditions préalables à Python et de nettoyer après les tests. Ils aident à s'assurer que les tests sont indépendants et peuvent fonctionner indépendamment.
Qu'est-ce que la couverture des tests et pourquoi est-ce important? La couverture des tests mesure le pourcentage de la base de code que vos tests exécutent. Il aide à identifier le code non testé et garantit que vos tests sont complets, réduisant ainsi la possibilité que les erreurs soient découvertes.
Quelles sont les meilleures pratiques pour rédiger des tests unitaires efficaces à Python? Oui, certaines meilleures pratiques incluent la rédaction de tests indépendants et isolés, en utilisant des noms de méthode de test descriptifs et tester les situations limites. De plus, essayez d'obtenir une bonne couverture de test et d'exécuter fréquemment des tests.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!