Dans notre équipe, nous définissons la plupart des cas de test comme ceci:
Une classe "framework" ourtcfw.py:
import unittest
class OurTcFw(unittest.TestCase):
def setUp:
# something
# other stuff that we want to use everywhere
et beaucoup de cas de test comme testMyCase.py:
import localweather
class MyCase(OurTcFw):
def testItIsSunny(self):
self.assertTrue(localweather.sunny)
def testItIsHot(self):
self.assertTrue(localweather.temperature > 20)
if __== "__main__":
unittest.main()
Lorsque j'écris un nouveau code de test et que je veux l'exécuter souvent pour gagner du temps, ce que je fais est de mettre "__" devant tous les autres tests. Mais c’est lourd, cela me distrait du code que j’écris et le bruit de commit que cela crée est tout simplement agaçant.
Donc, par exemple en apportant des modifications à testItIsHot()
, je veux pouvoir le faire:
$ python testMyCase.py testItIsHot
et avoir unittest
run seulementtestItIsHot()
Comment puis-je y arriver?
J'ai essayé de réécrire la partie if __== "__main__":
, mais comme je ne connais pas encore Python, je me sens perdu et je continue à fouiller dans tout ce qui est autre que les méthodes.
Cela fonctionne comme vous le suggérez - vous devez simplement spécifier le nom de la classe:
python testMyCase.py MyCase.testItIsHot
Si vous organisez vos cas de test, suivez la même organisation que le code réel et utilisez également les importations relatives pour les modules du même package.
Vous pouvez également utiliser le format de commande suivant:
python -m unittest mypkg.tests.test_module.TestClass.test_method
# In your case, this would be:
python -m unittest testMyCase.MyCase.testItIsHot
Documentation Python3 pour cela: https://docs.python.org/3/library/unittest.html#command-line-interface
Cela peut bien fonctionner comme vous le devinez
python testMyCase.py MyCase.testItIsHot
Et il existe un autre moyen de simplement tester testItIsHot
:
suite = unittest.TestSuite()
suite.addTest(MyCase("testItIsHot"))
runner = unittest.TextTestRunner()
runner.run(suite)
Si vous extrayez de l'aide du module unittest, il vous indique plusieurs combinaisons qui vous permettent d'exécuter des classes de cas de test à partir d'un module et des méthodes de test à partir d'une classe de cas de test.
python3 -m unittest -h
[...]
Examples:
python3 -m unittest test_module - run tests from test_module
python3 -m unittest module.TestClass - run tests from module.TestClass
python3 -m unittest module.Class.test_method - run specified test method
Il n'est pas nécessaire que vous définissiez une unittest.main()
comme comportement par défaut de votre module.
Peut-être que ce sera utile pour quelqu'un. Si vous souhaitez exécuter uniquement des tests d'une classe spécifique:
if __== "__main__":
unittest.main(MyCase())
Cela fonctionne pour moi dans python 3.6
Inspiré par @ yarkee je l'ai combiné avec une partie du code que j'ai déjà obtenu. Vous pouvez également appeler cela à partir d'un autre script, simplement en appelant la fonction run_unit_tests()
sans avoir besoin d'utiliser la ligne de commande, ou simplement en l'appelant à partir de la ligne de commande avec python3 my_test_file.py
.
import my_test_file
my_test_file.run_unit_tests()
Malheureusement, cela ne fonctionne que pour Python 3.3
ou supérieur:
import unittest
class LineBalancingUnitTests(unittest.TestCase):
@classmethod
def setUp(self):
self.maxDiff = None
def test_it_is_sunny(self):
self.assertTrue("a" == "a")
def test_it_is_hot(self):
self.assertTrue("a" != "b")
Code du coureur:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from .somewhere import LineBalancingUnitTests
def create_suite(classes, unit_tests_to_run):
suite = unittest.TestSuite()
unit_tests_to_run_count = len( unit_tests_to_run )
for _class in classes:
_object = _class()
for function_name in dir( _object ):
if function_name.lower().startswith( "test" ):
if unit_tests_to_run_count > 0 \
and function_name not in unit_tests_to_run:
continue
suite.addTest( _class( function_name ) )
return suite
def run_unit_tests():
runner = unittest.TextTestRunner()
classes = [
LineBalancingUnitTests,
]
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = [
"test_it_is_sunny",
# "test_it_is_hot",
]
runner.run( create_suite( classes, unit_tests_to_run ) )
if __== "__main__":
print( "\n\n" )
run_unit_tests()
En modifiant un peu le code, vous pouvez passer un tableau avec tous les tests unitaires que vous souhaitez appeler:
...
def run_unit_tests(unit_tests_to_run):
runner = unittest.TextTestRunner()
classes = \
[
LineBalancingUnitTests,
]
runner.run( suite( classes, unit_tests_to_run ) )
...
Et un autre fichier:
import my_test_file
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
"test_it_is_sunny",
# "test_it_is_hot",
]
my_test_file.run_unit_tests( unit_tests_to_run )
Vous pouvez également utiliser https://docs.python.org/3/library/unittest.html#load-tests-protocol et définir la méthode suivante sur votre module/fichier de test:
def load_tests(loader, standard_tests, pattern):
suite = unittest.TestSuite()
suite.addTest( LineBalancingUnitTests( 'test_it_is_sunny' ) )
return suite
Si vous souhaitez limiter l'exécution à un seul test, il vous suffit de définir le modèle de découverte de test sur le seul fichier dans lequel vous avez défini la fonction load_tests()
.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import unittest
test_pattern = 'mytest/module/name.py'
PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
loader = unittest.TestLoader()
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )
suite = loader.discover( start_dir, test_pattern )
runner = unittest.TextTestRunner( verbosity=2 )
results = runner.run( suite )
print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )
sys.exit( not results.wasSuccessful() )
Références:
En guise d'alternative au dernier exemple de programme principal, j'ai proposé la variante suivante après avoir lu l'implémentation de la méthode unittest.main()
:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import unittest
PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )
from testing_package import main_unit_tests_module
testNames = ["TestCaseClassName.test_nameHelloWorld"]
loader = unittest.TestLoader()
suite = loader.loadTestsFromNames( testNames, main_unit_tests )
runner = unittest.TextTestRunner(verbosity=2)
results = runner.run( suite )
print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )
sys.exit( not results.wasSuccessful() )