UnitTest Framework - Guide rapide

Le test unitaire est une méthode de test logiciel par laquelle des unités individuelles de code source, telles que les fonctions, les méthodes et la classe, sont testées pour déterminer si elles sont aptes à être utilisées. Intuitivement, on peut voir une unité comme la plus petite partie testable d'une application. Les tests unitaires sont des fragments de code court créés par les programmeurs au cours du processus de développement. Il constitue la base des tests de composants.

Les tests unitaires peuvent être effectués des deux manières suivantes:

Test manuel Test automatisé

L'exécution manuelle des cas de test sans aucune prise en charge d'outil est appelée test manuel.

  • Étant donné que les cas de test sont exécutés par les ressources humaines, il est très time consuming and tedious.

  • Comme les cas de test doivent être exécutés manuellement, plus de testeurs sont nécessaires pour les tests manuels.

  • Il est moins fiable car les tests peuvent ne pas être effectués avec précision à chaque fois en raison d'erreurs humaines.

  • Aucune programmation ne peut être effectuée pour écrire des tests sophistiqués qui récupèrent des informations cachées.

Prendre en charge les outils et exécuter les cas de test à l'aide d'un outil d'automatisation est appelé test d'automatisation.

  • Fast Automation exécute les cas de test beaucoup plus rapidement que les ressources humaines.

  • le investment over human resources is less car les cas de test sont exécutés à l'aide de l'outil d'automatisation.

  • Les tests d'automatisation exécutent exactement la même opération à chaque fois qu'ils sont exécutés et are more reliable.

  • Testeurs can program sophisticated tests pour faire ressortir des informations cachées.

JUnit est un framework de test unitaire pour le langage de programmation Java. JUnit a joué un rôle important dans le développement du développement piloté par les tests, et fait partie d'une famille de frameworks de tests unitaires collectivement connus sous le nom de xUnit qui ont été créés avec JUnit. Vous pouvez découvrir le didacticiel JUnit ici.

Le framework de tests unitaires Python, parfois appelé «PyUnit», est une version en langage Python de JUnit développée par Kent Beck et Erich Gamma. PyUnit fait partie de la bibliothèque standard Python à partir de la version 2.1 de Python.

Le cadre de test unitaire Python prend en charge l'automatisation des tests, le partage du code de configuration et d'arrêt pour les tests, l'agrégation des tests dans des collections et l'indépendance des tests par rapport au cadre de reporting. Le module unittest fournit des classes qui facilitent la prise en charge de ces qualités pour un ensemble de tests.

Ce didacticiel a été préparé pour les débutants afin de les aider à comprendre les fonctionnalités de base du framework de test Python. Après avoir terminé ce didacticiel, vous vous retrouverez à un niveau d'expertise modéré dans l'utilisation du cadre de test Python à partir duquel vous pourrez passer aux niveaux suivants.

Vous devez avoir une expertise raisonnable dans le développement de logiciels utilisant le langage Python. Notre didacticiel Python est un bon endroit pour commencer à apprendre Python. Une connaissance des bases des tests logiciels est également souhaitable.

Configuration de l'environnement

Les classes nécessaires pour écrire des tests se trouvent dans le module 'unittest'. Si vous utilisez des versions antérieures de Python (antérieures à Python 2.1), le module peut être téléchargé depuishttp://pyunit.sourceforge.net/. Cependant, le module unittest fait désormais partie de la distribution Python standard; par conséquent, il ne nécessite aucune installation séparée.

«unittest» prend en charge l'automatisation des tests, le partage du code de configuration et d'arrêt pour les tests, l'agrégation des tests en collections et l'indépendance des tests par rapport au cadre de reporting.

Le module unittest fournit des classes qui facilitent la prise en charge de ces qualités pour un ensemble de tests.

Pour ce faire, unittest prend en charge les concepts importants suivants -

  • test fixture- Cela représente la préparation nécessaire pour effectuer un ou plusieurs tests et toutes les actions de nettoyage associées. Cela peut impliquer, par exemple, la création de bases de données temporaires ou proxy, de répertoires ou le démarrage d'un processus serveur.

  • test case- C'est la plus petite unité de test. Cela vérifie une réponse spécifique à un ensemble particulier d'entrées. unittest fournit une classe de base,TestCase, qui peut être utilisé pour créer de nouveaux cas de test.

  • test suite- Il s'agit d'un ensemble de cas de test, de suites de tests ou des deux. Ceci est utilisé pour regrouper les tests qui doivent être exécutés ensemble. Les suites de tests sont implémentées par la classe TestSuite.

  • test runner- C'est un composant qui orchestre l'exécution des tests et fournit le résultat à l'utilisateur. Le coureur peut utiliser une interface graphique, une interface textuelle ou renvoyer une valeur spéciale pour indiquer les résultats de l'exécution des tests.

Créer un test unitaire

Les étapes suivantes sont impliquées dans l'écriture d'un test unitaire simple -

Step 1 - Importez le module unittest dans votre programme.

Step 2- Définissez une fonction à tester. Dans l'exemple suivant, la fonction add () doit être soumise à un test.

Step 3 - Créez un testcase en sous-classant unittest.TestCase.

Step 4- Définissez un test comme une méthode à l'intérieur de la classe. Le nom de la méthode doit commencer par «test».

Step 5- Chaque test appelle la fonction assert de la classe TestCase. Il existe de nombreux types d'affirmations. L'exemple suivant appelle la fonction assertEquals ().

Step 6 - La fonction assertEquals () compare le résultat de la fonction add () avec l'argument arg2 et lance assertionError si la comparaison échoue.

Step 7 - Enfin, appelez la méthode main () depuis le module unittest.

import unittest
def add(x,y):
   return x + y
   
class SimpleTest(unittest.TestCase):
   def testadd1(self):
      self.assertEquals(add(4,5),9)
      
if __name__ == '__main__':
   unittest.main()

Step 8 - Exécutez le script ci-dessus à partir de la ligne de commande.

C:\Python27>python SimpleTest.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Step 9 - Les trois suivants pourraient être les résultats possibles d'un test -

Sr.Non Message et description
1

OK

Le test réussit. «A» s'affiche sur la console.

2

FAIL

Le test échoue et déclenche une exception AssertionError. «F» s'affiche sur la console.

3

ERROR

Le test lève une exception autre que AssertionError. «E» s'affiche sur la console.

Ces résultats sont affichés sur la console par «.», «F» et «E» respectivement.

Interface de ligne de commande

Le module unittest peut être utilisé à partir de la ligne de commande pour exécuter un ou plusieurs tests.

python -m unittest test1
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method

unittest prend en charge les options de ligne de commande suivantes. Pour une liste de toutes les options de ligne de commande, utilisez la commande suivante -

Python –m unittest -h

Sr.Non Option et description
1

-h, --help

Montrez ce message

2

v, --verbose

Sortie verbeuse

3

-q, --quiet

Sortie minimale

4

-f, --failfast

Arrêter au premier échec

5

-c, --catch

Catch control-C et affichage des résultats

6

-b, --buffer

Buffer stdout et stderr pendant les exécutions de test

Ce chapitre décrit les classes et méthodes définies dans le module unittest. Il y a cinq classes principales dans ce module.

Classe TestCase

L'objet de cette classe représente la plus petite unité testable. Il contient les routines de test et fournit des crochets pour préparer chaque routine et pour le nettoyage par la suite.

Les méthodes suivantes sont définies dans la classe TestCase -

Sr.Non Méthode et description
1

setUp()

Méthode appelée pour préparer le montage d'essai. Ceci est appelé immédiatement avant d'appeler la méthode de test

2

tearDown()

Méthode appelée immédiatement après l'appel de la méthode de test et le résultat enregistré. Ceci est appelé même si la méthode de test a déclenché une exception,

3

setUpClass()

Une méthode de classe appelée avant les tests dans une exécution de classe individuelle.

4

tearDownClass()

Une méthode de classe appelée après l'exécution des tests dans une classe individuelle.

5

run(result = None)

Exécutez le test en collectant le résultat dans l'objet de résultat du test transmis comme résultat .

6

skipTest(reason)

L'appeler pendant une méthode de test ou setUp () ignore le test en cours.

sept

debug()

Exécutez le test sans collecter le résultat.

8

shortDescription()

Renvoie une description en une ligne du test.

Agencements

Il peut y avoir de nombreux tests écrits dans une classe TestCase. Ces méthodes de test peuvent nécessiter une connexion à la base de données, des fichiers temporaires ou d'autres ressources pour être initialisées. Ceux-ci sont appelés appareils. TestCase comprend un crochet spécial pour configurer et nettoyer tous les appareils nécessaires à vos tests. Pour configurer les appareils, remplacez setUp (). Pour nettoyer, remplacez tearDown ().

Dans l'exemple suivant, deux tests sont écrits dans la classe TestCase. Ils testent le résultat de l'addition et de la soustraction de deux valeurs. La méthode setup () initialise les arguments en fonction de shortDescription () de chaque test. La méthode teardown () sera exécutée à la fin de chaque test.

import unittest

class simpleTest2(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      if name == "Add":
         self.a = 10
         self.b = 20
         print name, self.a, self.b
      if name == "sub":
         self.a = 50
         self.b = 60
         print name, self.a, self.b
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
if __name__ == '__main__':
   unittest.main()

Exécutez le code ci-dessus à partir de la ligne de commande. Il donne la sortie suivante -

C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "test2.py", line 21, in testadd
      self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s

FAILED (failures = 1)

Appareil de classe

La classe TestCase a une méthode setUpClass () qui peut être remplacée pour s'exécuter avant l'exécution de tests individuels dans une classe TestCase. De même, la méthode tearDownClass () sera exécutée après tous les tests de la classe. Les deux méthodes sont des méthodes de classe. Par conséquent, ils doivent être décorés avec la directive @classmethod.

L'exemple suivant illustre l'utilisation de ces méthodes de classe -

import unittest

class TestFixtures(unittest.TestCase):

   @classmethod
   def setUpClass(cls):
      print 'called once before any tests in class'

   @classmethod
   def tearDownClass(cls):
      print '\ncalled once after all tests in class'

   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      print '\n',name
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def test1(self):
      """One"""
      result = self.a+self.b
      self.assertTrue(True)
   def test2(self):
      """Two"""
      result = self.a-self.b
      self.assertTrue(False)
      
if __name__ == '__main__':
unittest.main()

Classe TestSuite

Le cadre de test de Python fournit un mécanisme utile par lequel les instances de cas de test peuvent être regroupées en fonction des fonctionnalités qu'elles testent. Ce mécanisme est rendu disponible par la classe TestSuite dans le module unittest.

Les étapes suivantes sont impliquées dans la création et l'exécution d'une suite de tests.

Step 1 - Créez une instance de la classe TestSuite.

suite = unittest.TestSuite()

Step 2 - Ajoutez des tests dans une classe TestCase dans la suite.

suite.addTest(testcase class)

Step 3 - Vous pouvez également utiliser la méthode makeSuite () pour ajouter des tests à partir d'une classe

suite = unittest.makeSuite(test case class)

Step 4 - Des tests individuels peuvent également être ajoutés dans la suite.

suite.addTest(testcaseclass(""testmethod")

Step 5 - Créez un objet de la classe TestTestRunner.

runner = unittest.TextTestRunner()

Step 6 - Appelez la méthode run () pour exécuter tous les tests de la suite

runner.run (suite)

Les méthodes suivantes sont définies dans la classe TestSuite -

Sr.Non Méthode et description
1

addTest()

Ajoute une méthode de test dans la suite de tests.

2

addTests()

Ajoute des tests à partir de plusieurs classes TestCase.

3

run()

Exécute les tests associés à cette suite, en collectant le résultat dans l'objet de résultat de test

4

debug()

Exécute les tests associés à cette suite sans collecter le résultat.

5

countTestCases()

Renvoie le nombre de tests représentés par cet objet de test

L'exemple suivant montre comment utiliser la classe TestSuite -

import unittest
class suiteTest(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
def suite():
   suite = unittest.TestSuite()
##   suite.addTest (simpleTest3("testadd"))
##   suite.addTest (simpleTest3("testsub"))
   suite.addTest(unittest.makeSuite(simpleTest3))
   return suite
   
if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   runner.run (test_suite)

Vous pouvez expérimenter la méthode addTest () en décommentant les lignes et l'instruction de commentaire ayant la méthode makeSuite ().

Classe TestLoader

Le package unittest a la classe TestLoader qui est utilisée pour créer des suites de tests à partir de classes et de modules. Par défaut, l'instance unittest.defaultTestLoader est automatiquement créée lorsque la méthode unittest.main (0 est appelée. Une instance explicite permet cependant la personnalisation de certaines propriétés.

Dans le code suivant, les tests de deux classes sont collectés dans une liste à l'aide de l'objet TestLoader.

import unittest
testList = [Test1, Test2]
testLoad = unittest.TestLoader()

TestList = []
for testCase in testList:
   testSuite = testLoad.loadTestsFromTestCase(testCase)
   TestList.append(testSuite)
   
newSuite = unittest.TestSuite(TestList)
runner = unittest.TextTestRunner()
runner.run(newSuite)

Le tableau suivant présente une liste de méthodes de la classe TestLoader -

S. Non Méthode et description
1

loadTestsFromTestCase()

Renvoie une suite de tous les cas de tests contenus dans une classe TestCase

2

loadTestsFromModule()

Renvoie une suite de tous les cas de tests contenus dans le module donné.

3

loadTestsFromName()

Renvoie une suite de tous les cas de test avec un spécificateur de chaîne.

4

discover()

Trouvez tous les modules de test en récursant dans les sous-répertoires à partir du répertoire de démarrage spécifié et retournez un objet TestSuite

Classe TestResult

Cette classe est utilisée pour compiler des informations sur les tests qui ont réussi et les tests qui ont échoué. Un objet TestResult stocke les résultats d'un ensemble de tests. Une instance TestResult est renvoyée par la méthode TestRunner.run ().

Les instances TestResult ont les attributs suivants -

Sr.Non Attribut et description
1

Errors

Une liste contenant 2-tuples d'instances et de chaînes TestCase contenant des traces formatées. Chaque tuple représente un test qui a déclenché une exception inattendue.

2

Failures

Une liste contenant 2-tuples d'instances et de chaînes TestCase contenant des traces formatées. Chaque tuple représente un test où un échec a été signalé explicitement à l'aide des méthodes TestCase.assert * ().

3

Skipped

Une liste contenant 2-tuples d'instances et de chaînes TestCase contenant la raison pour laquelle le test a été ignoré.

4

wasSuccessful()

Renvoie True si tous les tests exécutés jusqu'à présent ont réussi, sinon renvoie False.

5

stop()

Cette méthode peut être appelée pour signaler que l'ensemble de tests en cours d'exécution doit être abandonné.

6

startTestRun()

Appelé une fois avant l'exécution des tests.

sept

stopTestRun()

Appelé une fois après l'exécution de tous les tests.

8

testsRun

Le nombre total de tests exécutés jusqu'à présent.

9

Buffer

Si défini sur true, sys.stdout et sys.stderr sera mis en mémoire tampon entre les appels de startTest () et stopTest ().

Le code suivant exécute une suite de tests -

if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   result = runner.run (test_suite)
   
   print "---- START OF TEST RESULTS"
   print result

   print "result::errors"
   print result.errors

   print "result::failures"
   print result.failures

   print "result::skipped"
   print result.skipped

   print "result::successful"
   print result.wasSuccessful()
   
   print "result::test-run"
   print result.testsRun
   print "---- END OF TEST RESULTS"

Le code lorsqu'il est exécuté affiche la sortie suivante -

---- START OF TEST RESULTS
<unittest.runner.TextTestResult run = 2 errors = 0 failures = 1>
result::errors
[]
result::failures
[(<__main__.suiteTest testMethod = testadd>, 'Traceback (most recent call last):\n
   File "test3.py", line 10, in testadd\n 
   self.assertTrue(result == 100)\nAssert
   ionError: False is not true\n')]
result::skipped
[]
result::successful
False
result::test-run
2
---- END OF TEST RESULTS

Le framework de test Python utilise la fonction assert () intégrée de Python qui teste une condition particulière. Si l'assertion échoue, une AssertionError sera déclenchée. Le cadre de test identifiera alors le test comme un échec. Les autres exceptions sont traitées comme une erreur.

Les trois ensembles de fonctions d'assertion suivants sont définis dans le module unittest -

  • Assertions booléennes de base
  • Assertions comparatives
  • Assertions pour les collections

Les fonctions d'assert de base évaluent si le résultat d'une opération est True ou False. Toutes les méthodes d'assert acceptent unmsg argument qui, s'il est spécifié, est utilisé comme message d'erreur en cas d'échec.

Sr.Non Méthode et description
1

assertEqual(arg1, arg2, msg = None)

Testez que arg1 et arg2 sont égaux. Si les valeurs ne sont pas égales, le test échouera.

2

assertNotEqual(arg1, arg2, msg = None)

Testez que arg1 et arg2 ne sont pas égaux. Si les valeurs sont égales, le test échouera.

3

assertTrue(expr, msg = None)

Vérifiez que expr est vrai. Si faux, le test échoue

4

assertFalse(expr, msg = None)

Vérifiez que expr est faux. Si vrai, le test échoue

5

assertIs(arg1, arg2, msg = None)

Testez que arg1 et arg2 évaluent le même objet.

6

assertIsNot(arg1, arg2, msg = None)

Testez que arg1 et arg2 ne correspondent pas au même objet.

sept

assertIsNone(expr, msg = None)

Testez que expr est None. Sinon Aucun, le test échoue

8

assertIsNotNone(expr, msg = None)

Testez que expr n'est pas None. Si aucun, le test échoue

9

assertIn(arg1, arg2, msg = None)

Testez que arg1 est dans arg2 .

dix

assertNotIn(arg1, arg2, msg = None)

Testez que arg1 n'est pas dans arg2 .

11

assertIsInstance(obj, cls, msg = None)

Tester que obj est une instance de cls

12

assertNotIsInstance(obj, cls, msg = None)

Tester que obj n'est pas une instance de cls

Certaines des fonctions d'assertion ci-dessus sont implémentées dans le code suivant -

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertEqual(4 + 5,9)
   def test2(self):
      self.assertNotEqual(5 * 2,10)
   def test3(self):
      self.assertTrue(4 + 5 == 9,"The result is False")
   def test4(self):
      self.assertTrue(4 + 5 == 10,"assertion fails")
   def test5(self):
      self.assertIn(3,[1,2,3])
   def test6(self):
      self.assertNotIn(3, range(5))

if __name__ == '__main__':
   unittest.main()

Lorsque le script ci-dessus est exécuté, test2, test4 et test6 afficheront un échec et les autres s'exécuteront avec succès.

FAIL: test2 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 9, in test2
      self.assertNotEqual(5*2,10)
AssertionError: 10 == 10

FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 13, in test4
      self.assertTrue(4+5==10,"assertion fails")
AssertionError: assertion fails

FAIL: test6 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 17, in test6
      self.assertNotIn(3, range(5))
AssertionError: 3 unexpectedly found in [0, 1, 2, 3, 4]

----------------------------------------------------------------------            
Ran 6 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 3)

Le deuxième ensemble de fonctions d'assertion est comparative asserts −

  • assertAlmostEqual (premier, deuxième, places = 7, msg = Aucun, delta = Aucun)

    Vérifiez que première et seconde sont à peu près (ou pas environ) correspondant en calculant la différence, arrondi au nombre donné de décimales endroits (par défaut 7),

  • assertNotAlmostEqual (premier, deuxième, lieux, msg, delta)

    Vérifiez que le premier et le second ne sont pas à peu près égaux en calculant la différence, en arrondissant au nombre donné de décimales (7 par défaut) et en comparant à zéro.

    Dans les deux fonctions ci-dessus, si delta est fourni au lieu de places, la différence entre le premier et le second doit être inférieure ou égale à (ou supérieure à) delta.

    Fournir à la fois delta et places déclenche une TypeError.

  • assertGreater (premier, deuxième, msg = Aucun)

    Vérifiez que le premier est supérieur à la seconde en fonction du nom de la méthode. Sinon, le test échouera.

  • assertGreaterEqual (premier, deuxième, msg = Aucun)

    Vérifiez que le premier est supérieur ou égal à second en fonction du nom de la méthode. Sinon, le test échouera

  • assertLess (premier, deuxième, msg = Aucun)

    Vérifiez que le premier est inférieur à la seconde en fonction du nom de la méthode. Sinon, le test échouera

  • assertLessEqual (premier, deuxième, msg = Aucun)

    Vérifiez que le premier est inférieur ou égal à second en fonction du nom de la méthode. Sinon, le test échouera.

  • assertRegexpMatches (texte, expression régulière, msg = Aucun)

    Vérifiez qu'une recherche d'expression régulière correspond au texte. En cas d'échec, le message d'erreur inclura le motif et le texte. regexp peut être un objet d'expression régulière ou une chaîne contenant une expression régulière pouvant être utilisée parre.search().

  • assertNotRegexpMatches (texte, expression régulière, msg = Aucun)

    Vérifie qu'une recherche d' expression régulière ne correspond pas au texte . Échoue avec un message d'erreur incluant le modèle et la partie de texte qui correspond. regexp peut être un objet d'expression régulière ou une chaîne contenant une expression régulière pouvant être utilisée parre.search().

Les fonctions d'assertion sont implémentées dans l'exemple suivant -

import unittest
import math
import re

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertAlmostEqual(22.0/7,3.14)
   def test2(self):
      self.assertNotAlmostEqual(10.0/3,3)
   def test3(self):
      self.assertGreater(math.pi,3)
   def test4(self):
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")

if __name__ == '__main__':
   unittest.main()

Le script ci-dessus signale test1 et test4 comme un échec. Dans le test 1, la division de 22/7 n'est pas comprise entre 7 décimales et 3,14. De même, puisque le deuxième argument correspond au texte du premier argument, test4 aboutit à AssertionError.

=====================================================FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 7, in test1
      self.assertAlmostEqual(22.0/7,3.14)
AssertionError: 3.142857142857143 != 3.14 within 7 places
================================================================
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 13, in test4
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
AssertionError: Regexp matched: 'Point' matches 'Point' in 'Tutorials Point (I)
Private Limited'
----------------------------------------------------------------------

Ran 4 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

Assert pour les collections

Cet ensemble de fonctions d'assertion est destiné à être utilisé avec des types de données de collection en Python, tels que List, Tuple, Dictionary et Set.

Sr.Non Méthode et description
1

assertListEqual (list1, list2, msg = None)

Teste que deux listes sont égales. Sinon, un message d'erreur est construit qui montre uniquement les différences entre les deux.

2

assertTupleEqual (tuple1, tuple2, msg = None)

Teste que deux tuples sont égaux. Sinon, un message d'erreur est construit qui montre uniquement les différences entre les deux.

3

assertSetEqual (set1, set2, msg = None)

Teste que deux ensembles sont égaux. Sinon, un message d'erreur est construit qui répertorie les différences entre les ensembles.

4

assertDictEqual (expected, actual, msg = None)

Vérifiez que deux dictionnaires sont égaux. Sinon, un message d'erreur est construit qui montre les différences dans les dictionnaires.

L'exemple suivant implémente les méthodes ci-dessus -

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertListEqual([2,3,4], [1,2,3,4,5])
   def test2(self):
      self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
   def test3(self):
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})

if __name__ == '__main__':
   unittest.main()

Dans l'exemple ci-dessus, test1 et test3 affichent AssertionError. Le message d'erreur affiche les différences entre les objets Liste et Dictionnaire.

FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 5, in test1
      self.assertListEqual([2,3,4], [1,2,3,4,5])
AssertionError: Lists differ: [2, 3, 4] != [1, 2, 3, 4, 5]

First differing element 0:
2
1

Second list contains 2 additional elements.
First extra element 3:
4

- [2, 3, 4]
+ [1, 2, 3, 4, 5]
? +++       +++

FAIL: test3 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 9, in test3
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
AssertionError: {1: 11, 2: 22} != {1: 11, 2: 22, 3: 33}
- {1: 11, 2: 22}
+ {1: 11, 2: 22, 3: 33}
?              +++++++
                                                                                  
----------------------------------------------------------------------            
Ran 3 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

La classe TestLoader a une fonction discover (). Le framework de test Python l'utilise pour une découverte de test simple. Pour être compatibles, les modules et packages contenant des tests doivent être importables à partir du répertoire de niveau supérieur.

Ce qui suit est l'utilisation de base de la ligne de commande de la découverte de test -

Python –m unittest discover

L'interpréteur tente de charger tous les modules contenant le test du répertoire courant et des répertoires internes de manière récursive. Les autres options de ligne de commande sont -

Sr.Non Options et description
1

-v, --verbose

Sortie verbeuse

2

-s, --start-directory

répertoire Répertoire pour démarrer la découverte (. par défaut)

3

-p, --pattern

pattern Pattern pour correspondre aux fichiers de test (test * .py par défaut)

4

-t, --top-level-directory

répertoire Répertoire de premier niveau du projet (par défaut, répertoire de démarrage)

Par exemple, pour découvrir les tests dans les modules dont les noms commencent par 'assert' dans le répertoire 'tests', la ligne de commande suivante est utilisée -

C:\python27>python –m unittest –v –s "c:\test" –p "assert*.py"

La découverte de tests charge les tests en les important. Une fois que la découverte de test a trouvé tous les fichiers de test dans le répertoire de démarrage que vous spécifiez, elle transforme les chemins en noms de package à importer.

Si vous fournissez le répertoire de démarrage comme nom de package plutôt que comme chemin d'accès à un répertoire, Discover suppose que l'emplacement à partir duquel il importe est l'emplacement souhaité, vous n'obtiendrez donc pas l'avertissement.

La prise en charge du saut de tests a été ajoutée depuis Python 2.7. Il est possible de sauter une méthode de test individuelle ou une classe TestCase, de manière conditionnelle et inconditionnelle. Le cadre permet à un certain test d'être marqué comme un «échec attendu». Ce test «échouera» mais ne sera pas compté comme ayant échoué dans TestResult.

Pour ignorer une méthode sans condition, la méthode de classe unittest.skip () suivante peut être utilisée -

import unittest

   def add(x,y):
      return x+y

class SimpleTest(unittest.TestCase):
   @unittest.skip("demonstrating skipping")
   def testadd1(self):
      self.assertEquals(add(4,5),9)

if __name__ == '__main__':
   unittest.main()

Puisque skip () est une méthode de classe, elle est préfixée par @ token. La méthode prend un argument: un message de journal décrivant la raison du saut.

Lorsque le script ci-dessus est exécuté, le résultat suivant s'affiche sur la console -

C:\Python27>python skiptest.py
s
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK (skipped = 1)

Le caractère «s» indique qu'un test a été ignoré.

Une autre syntaxe pour sauter le test consiste à utiliser la méthode d'instance skipTest () dans la fonction de test.

def testadd2(self):
   self.skipTest("another method for skipping")
   self.assertTrue(add(4 + 5) == 10)

Les décorateurs suivants implémentent le saut de test et les échecs attendus -

Sr.Non Méthode et description
1

unittest.skip(reason)

Ignorez sans condition le test décoré. la raison doit décrire pourquoi le test est ignoré.

2

unittest.skipIf(condition, reason)

Ignorez le test décoré si la condition est vraie.

3

unittest.skipUnless(condition, reason)

Ignorez le test décoré sauf si la condition est vraie.

4

unittest.expectedFailure()

Marquez le test comme un échec attendu. Si le test échoue lors de son exécution, le test n'est pas compté comme un échec.

L'exemple suivant illustre l'utilisation du saut conditionnel et de l'échec attendu.

import unittest

class suiteTest(unittest.TestCase):
   a = 50
   b = 40
   
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertEqual(result,100)

   @unittest.skipIf(a>b, "Skip over this routine")
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
   
   @unittest.skipUnless(b == 0, "Skip over this routine")
   def testdiv(self):
      """div"""
      result = self.a/self.b
      self.assertTrue(result == 1)

   @unittest.expectedFailure
   def testmul(self):
      """mul"""
      result = self.a*self.b
      self.assertEqual(result == 0)

if __name__ == '__main__':
   unittest.main()

Dans l'exemple ci-dessus, testsub () et testdiv () seront ignorés. Dans le premier cas a> b est vrai, tandis que dans le second cas b == 0 n'est pas vrai. D'autre part, testmul () a été marqué comme échec attendu.

Lorsque le script ci-dessus est exécuté, deux tests ignorés affichent «s» et l'échec attendu est indiqué par «x».

C:\Python27>python skiptest.py
Fsxs
================================================================
FAIL: testadd (__main__.suiteTest)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "skiptest.py", line 9, in testadd
      self.assertEqual(result,100)
AssertionError: 90 != 100

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures = 1, skipped = 2, expected failures = 1)

Le framework de test Python fournit les méthodes d'assertion suivantes pour vérifier que des exceptions sont déclenchées.

assertRaises (exception, appelable, * args, ** kwds)

Testez qu'une exception (premier argument) est déclenchée lorsqu'une fonction est appelée avec des arguments de position ou de mot-clé. Le test réussit si l'exception attendue est déclenchée, est une erreur si une autre exception est déclenchée ou échoue si aucune exception n'est déclenchée. Pour intercepter n'importe laquelle d'un groupe d'exceptions, un tuple contenant les classes d'exception peut être passé comme exception.

Dans l'exemple ci-dessous, une fonction de test est définie pour vérifier si ZeroDivisionError est déclenchée.

import unittest

def div(a,b):
   return a/b
class raiseTest(unittest.TestCase):
   def testraise(self):
      self.assertRaises(ZeroDivisionError, div, 1,0)

if __name__ == '__main__':
   unittest.main()

La fonction testraise () utilise la fonction assertRaises () pour voir si une division par zéro se produit lorsque la fonction div () est appelée. Le code ci-dessus lèvera une exception. Mais change les arguments en fonction div () comme suit -

self.assertRaises(ZeroDivisionError, div, 1,1)

Lorsqu'un code est exécuté avec ces modifications, le test échoue car ZeroDivisionError ne se produit pas.

F
================================================================
FAIL: testraise (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 7, in testraise
      self.assertRaises(ZeroDivisionError, div, 1,1)
AssertionError: ZeroDivisionError not raised

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures = 1)

assertRaisesRegexp (exception, expression régulière, appelable, * args, ** kwds)

Teste que l' expression rationnelle correspond à la représentation sous forme de chaîne de l'exception levée. regexp peut être un objet d'expression régulière ou une chaîne contenant une expression régulière pouvant être utilisée par re.search ().

L'exemple suivant montre comment assertRaisesRegexp () est utilisé -

import unittest
import re

class raiseTest(unittest.TestCase):
   def testraiseRegex(self):
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
      
if __name__ == '__main__':
   unittest.main()

Ici, le test testraseRegex () n'échoue pas en tant que premier argument. "Point" se trouve dans la deuxième chaîne d'argument.

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:/Python27/raiseTest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
AssertionError: TypeError not raised
----------------------------------------------------------------------

Cependant, le changement est comme indiqué ci-dessous -

self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")

Une exception TypeError sera levée. Par conséquent, le résultat suivant sera affiché -

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")
AssertionError: "invalid" does not match 
   "first argument must be string or compiled pattern"
----------------------------------------------------------------------

Junit, le framework de test unitaire Java (Pyunit est l'implémentation de JUnit) a une option pratique de timeout. Si un test prend plus de temps que spécifié, il sera marqué comme ayant échoué.

Le cadre de test de Python ne contient aucun support pour le délai d'expiration. Cependant, un troisième module appelé timeout-decorator peut faire le travail.

Téléchargez et installez le module à partir de -

https://pypi.python.org/packages/source/t/timeout-decorator/timeout-decorator-0.3.2.tar.gz

  • Importer timeout_decorator dans le code
  • Mettre le décorateur de délai avant le test
  • @timeout_decorator.timeout(10)

Si une méthode de test en dessous de cette ligne prend plus que le délai mentionné (10 minutes) ici, une TimeOutError sera déclenchée. Par exemple -

import time
import timeout_decorator

class timeoutTest(unittest.TestCase):

   @timeout_decorator.timeout(5)
   def testtimeout(self):
      print "Start"
   for i in range(1,10):
      time.sleep(1)
      print "%d seconds have passed" % i
      
if __name__ == '__main__':
   unittest.main()

unittest2 est un backport de fonctionnalités supplémentaires ajoutées au framework de test Python dans Python 2.7 et versions ultérieures. Il est testé pour fonctionner sur Python 2.6, 2.7 et 3. *. La dernière version peut être téléchargée depuishttps://pypi.python.org/pypi/unittest2

Pour utiliser unittest2 au lieu de unittest, remplacez simplement import unittest par import unittest2.

Les classes dans unittest2 dérivent des classes appropriées dans unittest, il devrait donc être possible d'utiliser l'infrastructure d'exécution des tests unittest2 sans avoir à basculer immédiatement tous vos tests vers unittest2. Si vous avez l'intention de mettre en œuvre de nouvelles fonctionnalités, sous-classez votre cas de test deunittest2.TestCase au lieu de unittest.TestCase

Voici les nouvelles fonctionnalités d'unittest2 -

  • addCleanups pour une meilleure gestion des ressources

  • Contient de nombreuses nouvelles méthodes d'assert

  • assertRaises en tant que gestionnaire de contexte, avec accès à l'exception par la suite

  • Possède des appareils de niveau de module tels que setUpModule et tearDownModule

  • Comprend load_tests protocole de chargement de tests à partir de modules ou de packages

  • startTestRun et stopTestRun méthodes sur TestResult

Dans Python 2.7, vous appelez les fonctionnalités de ligne de commande unittest (y compris la découverte de test) avec python -m unittest <args>.

Au lieu de cela, unittest2 est livré avec un script unit2.

unit2 discover
unit2 -v test_module

Une gestion plus efficace de control-C pendant une exécution de test est fournie par l'option de ligne de commande -c / - catch pour unittest, avec l'option catchbreakparamètre. Avec le comportement catch break activé, control-C permettra au test en cours de se terminer, et l'exécution du test se terminera et rapportera tous les résultats jusqu'à présent. Un second control-c lèvera un KeyboardInterrupt de la manière habituelle.

Si le gestionnaire unittest est appelé mais que le gestionnaire signal.SIGINT n'est pas installé, il appelle le gestionnaire par défaut. Ce sera normalement le comportement attendu par le code qui remplace un gestionnaire installé et lui délègue. Pour les tests individuels qui nécessitent une gestion unittest control-c désactivée, le décorateur removeHandler () peut être utilisé.

Les fonctions utilitaires suivantes activent la fonctionnalité de gestion control-c dans les cadres de test -

unittest.installHandler ()

Installez le gestionnaire control-c. Lorsqu'unsignal.SIGINT est reçu tous les résultats enregistrés ont TestResult.stop () appelé.

unittest.registerResult (résultat)

Enregistrer un TestResultobjet pour la gestion control-c. L'enregistrement d'un résultat stocke une référence faible à celui-ci, ce qui n'empêche pas le résultat d'être récupéré.

unittest.removeResult (résultat)

Supprimez un résultat enregistré. Une fois qu'un résultat a été supprimé, TestResult.stop () ne sera plus appelé sur cet objet de résultat en réponse à un contrôle-c.

unittest.removeHandler (fonction = Aucun)

Lorsqu'elle est appelée sans arguments, cette fonction supprime le gestionnaire control-c s'il a été installé. Cette fonction peut également être utilisée comme décorateur de test pour supprimer temporairement le gestionnaire pendant l'exécution du test.

Testeur de l'interface graphique

Le module unittest est installé pour découvrir et exécuter des tests de manière interactive. Cet utilitaire, un script Python 'inittestgui.py' utilise le module Tkinter qui est un port Python pour le kit d'outils graphiques TK. Il donne une interface graphique facile à utiliser pour la découverte et l'exécution de tests.

Python unittestgui.py

Cliquez sur le bouton «Découvrir les tests». Une petite boîte de dialogue apparaît dans laquelle vous pouvez sélectionner le répertoire et les modules à partir desquels le test doit être exécuté.

Enfin, cliquez sur le bouton Démarrer. Les tests seront découverts à partir du chemin et des noms de module sélectionnés, et le volet des résultats affichera les résultats.

Pour voir les détails du test individuel, sélectionnez et cliquez sur test dans la zone de résultat -

Si vous ne trouvez pas cet utilitaire dans l'installation de Python, vous pouvez l'obtenir à partir de la page du projet http://pyunit.sourceforge.net/.

Un utilitaire similaire basé sur la boîte à outils wxpython y est également disponible.

La distribution standard de Python contient le module «Doctest». La fonctionnalité de ce module permet de rechercher des morceaux de texte qui ressemblent à des sessions Python interactives, et exécute ces sessions pour voir si elles fonctionnent exactement comme indiqué.

Doctest peut être très utile dans les scénarios suivants -

  • Pour vérifier que les docstrings d'un module sont à jour en vérifiant que tous les exemples interactifs fonctionnent toujours comme documenté.

  • Pour effectuer des tests de régression en vérifiant que les exemples interactifs d'un fichier de test ou d'un objet de test fonctionnent comme prévu.

  • Pour rédiger la documentation du didacticiel pour un package, largement illustrée par des exemples d'entrée-sortie

En Python, une «docstring» est une chaîne littérale qui apparaît comme la première expression dans une classe, une fonction ou un module. Il est ignoré lorsque la suite est exécutée, mais il est reconnu par le compilateur et placé dans le__doc__attribut de la classe, de la fonction ou du module englobant. Puisqu'il est disponible via l'introspection, c'est le lieu canonique de documentation de l'objet.

Il est courant de mettre des exemples d'utilisation de différentes parties du code Python dans la docstring. Le module doctest permet de vérifier que ces docstrings sont à jour avec les révisions intermittentes du code.

Dans le code suivant, une fonction factorielle est définie entrecoupée d'exemples d'utilisation. Afin de vérifier si l'utilisation de l'exemple est correcte, appelez la fonction testmod () dans le module doctest.

"""
This is the "example" module.

The example module supplies one function, factorial(). For example,

>>> factorial(5)
120
"""

def factorial(x):
   """Return the factorial of n, an exact integer >= 0.
   >>> factorial(-1)
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
   """
   
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testmod()

Entrez et enregistrez le script ci-dessus sous FactDocTest.py et essayez d'exécuter ce script à partir de la ligne de commande.

Python FactDocTest.py

Aucune sortie ne sera affichée sauf si l'exemple échoue. Maintenant, changez la ligne de commande comme suit -

Python FactDocTest.py –v

La console affichera maintenant la sortie suivante -

C:\Python27>python FactDocTest.py -v
Trying:
   factorial(5)
Expecting:
   120
ok
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
2 items passed all tests:
   1 tests in __main__
   1 tests in __main__.factorial
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

Si, par contre, le code de la fonction factorial () ne donne pas le résultat attendu dans docstring, le résultat de l'échec sera affiché. Par exemple, changez f = 2 à la place de f = 1 dans le script ci-dessus et exécutez à nouveau le doctest. Le résultat sera le suivant -

Trying:
   factorial(5)
Expecting:
   120
**********************************************************************
File "docfacttest.py", line 6, in __main__
Failed example:
factorial(5)
Expected:
   120
Got:
   240
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
1 items passed all tests:
   1 tests in __main__.factorial
**********************************************************************
1 items had failures:
   1 of 1 in __main__
2 tests in 2 items.
1 passed and 1 failed.
***Test Failed*** 1 failures.

Doctest: vérification d'exemples dans un fichier texte

Une autre application simple de doctest consiste à tester des exemples interactifs dans un fichier texte. Cela peut être fait avec la fonction testfile ().

Le texte suivant est stocké dans un fichier texte nommé «exemple.txt».

Using ''factorial''
-------------------
This is an example text file in reStructuredText format. First import
''factorial'' from the ''example'' module:
   >>> from example import factorial
Now use it:
   >>> factorial(5)
   120

Le contenu du fichier est traité comme docstring. Afin de vérifier les exemples dans le fichier texte, utilisez la fonction testfile () du module doctest.

def factorial(x):
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testfile("example.txt")
  • Comme avec le testmod (), testfile () n'affichera rien sauf si un exemple échoue. Si un exemple échoue, alors le (s) exemple (s) défaillant (s) et la ou les causes de l'échec (s) sont imprimés sur la console, en utilisant le même format que testmod ().

  • Dans la plupart des cas, un copier-coller d'une session de console interactive fonctionne bien, mais doctest n'essaie pas de faire une émulation exacte d'un shell Python spécifique.

  • Toute sortie attendue doit immédiatement suivre la ligne finale '>>>' ou '...' contenant le code, et la sortie attendue (le cas échéant) s'étend à la ligne suivante '>>>' ou entièrement blanche.

  • La sortie attendue ne peut pas contenir une ligne entièrement blanche, car une telle ligne est prise pour signaler la fin de la sortie attendue. Si la sortie attendue contient une ligne vide, mettez <BLANKLINE> dans votre exemple de doctest à chaque endroit où une ligne vide est attendue.

L'API doctest s'articule autour des deux classes de conteneurs suivantes utilisées pour stocker des exemples interactifs à partir de docstrings -

  • Example - Une seule instruction Python, associée à sa sortie attendue.

  • DocTest - Une collection d'exemples, généralement extraits d'une seule docstring ou d'un fichier texte.

Les classes de traitement supplémentaires suivantes sont définies pour rechercher, analyser, exécuter et vérifier les exemples de doctest -

  • DocTestFinder - Recherche toutes les docstrings dans un module donné et utilise un DocTestParser pour créer un DocTest à partir de chaque docstring contenant des exemples interactifs.

  • DocTestParser - Crée un objet doctest à partir d'une chaîne (comme la docstring d'un objet).

  • DocTestRunner - Exécute les exemples dans un doctest et utilise un OutputChecker pour vérifier leur sortie.

  • OutputChecker - Compare la sortie réelle d'un exemple doctest avec la sortie attendue et décide si elles correspondent.

Classe DocTestFinder

C'est une classe de traitement utilisée pour extraire les doctests qui sont pertinents pour un objet donné, de sa docstring et des docstrings de ses objets contenus. Les doctests peuvent actuellement être extraits des types d'objets suivants - modules, fonctions, classes, méthodes, méthodes statiques, méthodes de classe et propriétés.

Cette classe définit la méthode find (). Il renvoie une liste des DocTests définis par la docstring de l' objet , ou par l'une des docstrings de ses objets contenus.

Classe DocTestParser

Il s'agit d'une classe de traitement utilisée pour extraire des exemples interactifs d'une chaîne et les utiliser pour créer un objet DocTest. Cette classe définit les méthodes suivantes -

  • get_doctest() - Extrayez tous les exemples doctest de la chaîne donnée et rassemblez-les dans un DocTest objet.

  • get_examples(string[, name]) - Extraire tous les exemples de doctest de la chaîne donnée et les renvoyer sous forme de liste de Exampleobjets. Les numéros de ligne sont basés sur 0. Le nom de l'argument facultatif est un nom identifiant cette chaîne et n'est utilisé que pour les messages d'erreur.

  • parse(string[, name]) - Divisez la chaîne donnée en exemples et texte intermédiaire, et renvoyez-les sous forme de liste Exampleset des cordes. Numéros de ligne pour leExamplessont basés sur 0. Le nom de l'argument facultatif est un nom identifiant cette chaîne et n'est utilisé que pour les messages d'erreur.

Classe DocTestRunner

Il s'agit d'une classe de traitement utilisée pour exécuter et vérifier les exemples interactifs dans un DocTest. Les méthodes suivantes y sont définies -

report_start ()

Signaler que le testeur est sur le point de traiter l'exemple donné. Cette méthode est fournie pour autoriser les sous-classes deDocTestRunnerpour personnaliser leur sortie; il ne doit pas être appelé directement

report_success ()

Signalez que l'exemple donné s'est exécuté avec succès. Cette méthode est fournie pour permettre aux sous-classes de DocTestRunner de personnaliser leur sortie; il ne doit pas être appelé directement.

report_failure ()

Signaler que l'exemple donné a échoué. Cette méthode est fournie pour autoriser les sous-classes deDocTestRunnerpour personnaliser leur sortie; il ne doit pas être appelé directement.

report_unexpected_exception ()

Signaler que l'exemple donné a soulevé une exception inattendue. Cette méthode est fournie pour permettre aux sous-classes de DocTestRunner de personnaliser leur sortie; il ne doit pas être appelé directement.

exécuter (test)

Exécutez les exemples dans test (un objet DocTest) et affichez les résultats à l'aide de la fonction d'écriture out .

résumer ([verbeux])

Imprimez un résumé de tous les cas de test qui ont été exécutés par ce DocTestRunner et retournez un tuple nommé TestResults (échec, tentative). L' argument détaillé facultatif contrôle le niveau de détail du résumé. Si la verbosité n'est pas spécifiée, la verbosité du DocTestRunner est utilisée.

Classe OutputChecker

Cette classe est utilisée pour vérifier si la sortie réelle d'un exemple doctest correspond à la sortie attendue.

Les méthodes suivantes sont définies dans cette classe -

check_output ()

Revenir Truesi la sortie réelle d'un exemple ( obtenu ) correspond à la sortie attendue ( souhaitée ). Ces chaînes sont toujours considérées comme identiques si elles sont identiques; mais en fonction de l'option que le lanceur de test utilise, plusieurs types de correspondance non exacte sont également possibles. Voir la section Indicateurs d'option et directives pour plus d'informations sur les indicateurs d'option.

output_difference ()

Renvoie une chaîne décrivant les différences entre la sortie attendue pour un exemple donné ( exemple ) et la sortie réelle ( got ).

Intégration de DocTest avec Unittest

Le module doctest fournit deux fonctions qui peuvent être utilisées pour créer des suites de tests unittest à partir de modules et de fichiers texte contenant des doctests. Pour intégrer avec unittest test discovery, incluez une fonction load_tests () dans votre module de test -

import unittest
import doctest
import doctestexample

def load_tests(loader, tests, ignore):
   tests.addTests(doctest.DocTestSuite(doctestexample))
   return tests

Une TestSuite combinée de tests de unittest ainsi que de doctest sera formée et elle peut maintenant être exécutée par la méthode main () ou run () du module unittest.

Voici les deux principales fonctions de création unittest.TestSuite instances de fichiers texte et modules avec les doctests -

doctest.DocFileSuite ()

Il est utilisé pour convertir les tests doctest d'un ou plusieurs fichiers texte en un unittest.TestSuite. Unittest.TestSuite retourné doit être exécuté par le framework unittest et exécute les exemples interactifs dans chaque fichier. Si l'un des exemples d'un fichier échoue, le test unitaire synthétisé échoue et unfailureException l'exception est levée indiquant le nom du fichier contenant le test et un numéro de ligne (parfois approximatif).

doctest.DocTestSuite ()

Il est utilisé pour convertir les tests doctest d'un module en un unittest.TestSuite.

Unittest.TestSuite retourné doit être exécuté par le framework unittest et exécute chaque doctest dans le module. Si l'un des doctests échoue, le test unitaire synthétisé échoue et unfailureException l'exception est levée indiquant le nom du fichier contenant le test et un numéro de ligne (parfois approximatif)

Sous les couvertures, DocTestSuite () crée un unittest.TestSuite hors des instances doctest.DocTestCase, et DocTestCase est une sous-classe de unittest.TestCase.

De même, DocFileSuite () crée un unittest.TestSuite à partir des instances doctest.DocFileCase, et DocFileCase est une sous-classe de DocTestCase.

Donc, les deux façons de créer une instance unittest.TestSuite exécutent DocTestCase. Lorsque vous exécutez vous-même les fonctions doctest, vous pouvez contrôler directement les options doctest utilisées, en passant des indicateurs d'option aux fonctions doctest.

Cependant, si vous écrivez un framework unittest, unittest contrôle finalement quand et comment les tests sont exécutés. L'auteur du framework veut généralement contrôler les options de rapport doctest (peut-être, par exemple, spécifié par les options de ligne de commande), mais il n'y a aucun moyen de passer des options via unittest aux exécuteurs de test doctest.

C'est en 2004 que Holger Krekel renomma son stdpackage, dont le nom était souvent confondu avec celui de la bibliothèque standard fournie avec Python, au nom (légèrement moins déroutant) 'py'. Bien que le paquet contienne plusieurs sous-paquets, il est maintenant presque entièrement connu pour son framework py.test.

Le framework py.test a mis en place un nouveau standard pour les tests Python et est devenu très populaire auprès de nombreux développeurs aujourd'hui. Les idiomes élégants et pythoniques qu'il a introduits pour l'écriture de tests ont permis d'écrire des suites de tests dans un style beaucoup plus compact.

py.test est une alternative sans passe-partout au module unittest standard de Python. Bien qu'il s'agisse d'un outil de test complet et extensible, il se vante d'une syntaxe simple. Créer une suite de tests est aussi simple que d'écrire un module avec quelques fonctions.

py.test fonctionne sur tous les systèmes d'exploitation POSIX et WINDOWS (XP / 7/8) avec les versions Python 2.6 et supérieures.

Installation

Utilisez le code suivant pour charger le module pytest dans la distribution Python actuelle ainsi qu'un utilitaire py.test.exe. Les tests peuvent être exécutés en utilisant les deux.

pip install pytest

Usage

Vous pouvez simplement utiliser l'instruction assert pour affirmer les attentes du test. L'introspection d'assert de pytest rapportera intelligemment les valeurs intermédiaires de l'expression d'assert, vous libérant ainsi du besoin d'apprendre les nombreux noms deJUnit legacy methods.

# content of test_sample.py
def func(x):
   return x + 1
   
def test_answer():
   assert func(3) == 5

Utilisez la ligne de commande suivante pour exécuter le test ci-dessus. Une fois le test exécuté, le résultat suivant s'affiche sur la console -

C:\Python27>scripts\py.test -v test_sample.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyth
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 1 items
test_sample.py::test_answer FAILED
================================== FAILURES =====================
_________________________________ test_answer _________________________________
   def test_answer():
>  assert func(3) == 5
E     assert 4 == 5
E     + where 4 = func(3)
test_sample.py:7: AssertionError
========================== 1 failed in 0.05 seconds ====================

Le test peut également être exécuté à partir de la ligne de commande en incluant le module pytest à l'aide du commutateur –m.

python -m pytest test_sample.py

Regroupement de plusieurs tests dans une classe

Une fois que vous commencez à avoir plus de quelques tests, il est souvent judicieux de regrouper les tests de manière logique, en classes et en modules. Écrivons une classe contenant deux tests -

class TestClass:
   def test_one(self):
      x = "this"
      assert 'h' in x
   def test_two(self):
      x = "hello"
      assert hasattr(x, 'check')

Le résultat du test suivant sera affiché -

C:\Python27>scripts\py.test -v test_class.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyt
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 2 items
test_class.py::TestClass::test_one PASSED
test_class.py::TestClass::test_two FAILED
================================== FAILURES =====================
_____________________________ TestClass.test_two ______________________________
self = <test_class.TestClass instance at 0x01309DA0>

   def test_two(self):
      x = "hello"
>  assert hasattr(x, 'check')
E     assert hasattr('hello', 'check')

test_class.py:7: AssertionError
===================== 1 failed, 1 passed in 0.06 seconds ======================

Le projet de nez est sorti en 2005, l'année d'après py.testa reçu sa forme moderne. Il a été écrit par Jason Pellerin pour prendre en charge les mêmes idiomes de test que ceux mis au point par py.test, mais dans un package plus facile à installer et à maintenir.

le nose le module peut être installé à l'aide de l'utilitaire pip

pip install nose

Cela installera le module nose dans la distribution Python actuelle ainsi qu'un nosetest.exe, ce qui signifie que le test peut être exécuté en utilisant cet utilitaire ainsi qu'en utilisant le commutateur –m.

C:\python>nosetests –v test_sample.py
Or
C:\python>python –m nose test_sample.py

nose collecte les tests de unittest.TestCasesous-classes, bien sûr. Nous pouvons également écrire des fonctions de test simples, ainsi que des classes de test qui ne sont pas des sous-classes d'unittest.TestCase. nose fournit également un certain nombre de fonctions utiles pour l'écriture de tests chronométrés, les tests d'exceptions et d'autres cas d'utilisation courants.

nosecollecte les tests automatiquement. Il n'est pas nécessaire de collecter manuellement les cas de test dans des suites de tests. L'exécution des tests est réactive, carnose commence à exécuter les tests dès que le premier module de test est chargé.

Comme pour le module unittest, nose prend en charge les fixtures au niveau du package, du module, de la classe et du cas de test, une initialisation coûteuse peut donc être effectuée aussi rarement que possible.

Utilisation de base

Considérons nosetest.py similaire au script utilisé précédemment -

# content of nosetest.py
def func(x):
   return x + 1
   
def test_answer():
   assert func(3) == 5

Afin d'exécuter le test ci-dessus, utilisez la syntaxe de ligne de commande suivante -

C:\python>nosetests –v nosetest.py

La sortie affichée sur la console sera la suivante -

nosetest.test_answer ... FAIL
================================================================
FAIL: nosetest.test_answer
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python34\lib\site-packages\nose\case.py", line 198, in runTest
      self.test(*self.arg)
   File "C:\Python34\nosetest.py", line 6, in test_answer
      assert func(3) == 5
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures = 1)

nose peut être intégré à DocTest en utilisant with-doctest option dans la ligne de commande ci-dessus.

\nosetests --with-doctest -v nosetest.py

Vous pouvez utiliser nose dans un script de test -

import nose
nose.main()

Si vous ne souhaitez pas que le script de test se termine avec 0 en cas de succès et 1 en cas d'échec (comme unittest.main), utilisez plutôt nose.run () -

import nose
result = nose.run()

Le résultat sera vrai si l'exécution du test réussit, ou faux s'il échoue ou déclenche une exception non interceptée.

noseprend en charge les fixtures (méthodes de configuration et de démontage) au niveau du package, du module, de la classe et du test. Comme pour les fixtures py.test ou unittest, la configuration s'exécute toujours avant tout test (ou collection de tests pour les packages et modules de test); le démontage s'exécute si la configuration s'est terminée avec succès, quel que soit l'état du test.

Le module nose.tools fournit un certain nombre d'outils de test que vous pouvez trouver utiles, y compris des décorateurs pour restreindre le temps d'exécution des tests et tester les exceptions, et toutes les mêmes méthodes assertX que celles trouvées dans unittest.TestCase.

  • nose.tools.ok_(expr, msg = None) - Raccourci pour affirmer.

  • nose.tools.eq_(a, b, msg = None) - Raccourci pour 'assert a == b, "% r! =% R"% (a, b)

  • nose.tools.make_decorator(func) - Enveloppe un décorateur de test afin de reproduire correctement les métadonnées de la fonction décorée, y compris les éléments supplémentaires du nez (à savoir, la configuration et le démontage).

  • nose.tools.raises(*exceptions) - Le test doit déclencher l'une des exceptions attendues pour réussir.

  • nose.tools.timed(limit) - Le test doit se terminer dans le délai spécifié pour réussir

  • nose.tools.istest(func) - Décorateur pour marquer une fonction ou une méthode comme test

  • nose.tools.nottest(func) - Décorateur pour marquer une fonction ou une méthode comme n'étant pas un test

Test paramétré

Le cadre de test de Python, unittest, ne dispose pas d'un moyen simple d'exécuter des cas de test paramétrés. En d'autres termes, vous ne pouvez pas facilement passer d'arguments dans ununittest.TestCase de dehors.

Cependant, les ports du module pytest testent la paramétrisation de plusieurs manières bien intégrées -

  • pytest.fixture() permet de définir la paramétrisation au niveau des fonctions de l'appareil.

  • @pytest.mark.parametrizepermet de définir la paramétrisation au niveau de la fonction ou de la classe. Il fournit plusieurs ensembles d'arguments / appareils pour une fonction ou une classe de test particulière.

  • pytest_generate_tests permet d'implémenter votre propre schéma ou extensions de paramétrage dynamique personnalisé.

Un module tiers 'nose-parameterized' permet des tests paramétrés avec n'importe quel framework de test Python. Il peut être téléchargé à partir de ce lien -https://github.com/wolever/nose-parameterized