Question

J'ai un fichier de test qui contient des tests qui prennent tout à fait beaucoup de temps (ils envoient des calculs à un cluster et attendre le résultat). Tous ces éléments sont en classe TestCase spécifiques.

Comme ils prennent du temps et de plus ne sont pas susceptibles de se briser, je veux être en mesure de choisir si ce sous-ensemble de tests ou ne fonctionne pas (la meilleure façon serait un argument de ligne de commande, à savoir " ./tests.py --offline » ou quelque chose comme ça), je pouvais courir la plupart des tests souvent et rapidement et l'ensemble de temps en temps, quand j'ai le temps.

Pour l'instant, je viens d'utiliser pour démarrer les unittest.main() tests.

Merci.

Était-ce utile?

La solution

La valeur par défaut utilise le chargeur unittest.main() de test par défaut pour faire un GroupTest hors du module dans lequel principale est en cours d'exécution.

Vous ne devez pas utiliser ce comportement par défaut.

Vous pouvez, par exemple, faire trois instances unittest.TestSuite .

  1. Le sous-ensemble "rapide".

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. Le sous-ensemble "lent".

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. Le set "ensemble".

    alltests = unittest.TestSuite([fast, slow])
    

Notez que j'ai ajusté les noms de TestCase pour indiquer rapide par rapport lent. Vous pouvez sous-classe unittest.TestLoader pour analyser les noms des classes et créer plusieurs chargeurs.

Ensuite, votre programme principal peut analyser les arguments de ligne de commande avec optparse ou argparse (disponible depuis 2.7 ou 3.2) pour choisir quelle suite, vous voulez exécuter, rapide, lent ou tout.

Ou bien, vous pouvez avoir confiance que est l'une des sys.argv[1] trois valeurs et d'utiliser quelque chose d'aussi simple que cela

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Autres conseils

Pour exécuter un seul test spécifique, vous pouvez utiliser:

$ python -m unittest test_module.TestClass.test_method

Plus d'informations

En fait, on peut passer les noms des cas de test sys.argv et seuls les cas seront testés.

Par exemple, supposons que vous avez

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

Vous pouvez appeler

python test.py account

pour des tests uniquement de compte, ou même

$ python test.py account customer

pour que les deux cas testés

Je fais cela à l'aide d'un simple skipIf:

import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

De cette façon je besoin que décore un cas de test déjà existant avec cette ligne unique (pas besoin de créer des suites de test ou similaire, juste que l'on os.getenv() ligne d'appel au début de mon dossier de test unitaire), et par défaut ce test se sautée.

Si je veux l'exécuter en dépit d'être lent, je viens d'appeler mon script comme ceci:

SLOW_TESTS=1 python -m unittest …

Vous avez deux façons de le faire:

  1. Définissez votre propre suite de tests pour la classe
  2. Créer des classes simulées de la connexion du cluster qui renverra les données réelles.

Je suis un fervent partisan de l'approche qu'il seconde; un test unitaire devrait seul test une unité même de code, et non pas des systèmes complexes (comme les bases de données ou clusters). Mais je comprends qu'il ne soit pas toujours possible; parfois, la création de maquettes est tout simplement trop cher, ou le but du test est vraiment dans le système complexe.

Retour à l'option (1), vous pouvez procéder ainsi:

suite = unittest.TestSuite()
suite.addTest(MyUnitTestClass('quickRunningTest'))
suite.addTest(MyUnitTestClass('otherTest'))

et en faisant passer la suite au coureur de test:

unittest.TextTestRunner().run(suite)

Plus d'informations sur la documentation python: http://docs.python.org /library/unittest.html#testsuite-objects

Puisque vous utilisez, vous pouvez simplement unittest.main() exécuter pour obtenir la python tests.py --help documentation:

Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase

C'est, vous pouvez simplement faire

python tests.py TestClass.test_method

Vous pouvez également utiliser la fonction unittest.SkipTest(). Exemple, ajoutez une méthode à votre classe skipOrRunTest de test comme ceci:

def skipOrRunTest(self,testType):
    #testsToRun = 'ALL'
    #testsToRun = 'testType1, testType2, testType3, testType4,...etc'
    #testsToRun = 'testType1'
    #testsToRun = 'testType2'
    #testsToRun = 'testType3'
    testsToRun = 'testType4'              
    if ((testsToRun == 'ALL') or (testType in testsToRun)):
        return True 
    else:
        print "SKIPPED TEST because:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

Ensuite, ajoutez un appel à cette méthode skipOrRunTest au début de chacun de vos tests unitaires comme ceci:

def testType4(self):
    self.skipOrRunTest('testType4')

J'ai trouvé une autre solution, basée sur la façon dont le décorateur fonctionne unittest.skip. En définissant la et __unittest_skip__ __unittest_skip_why__.

à base de labels

Je voulais appliquer un système d'étiquetage, d'étiqueter certains tests comme quick, slow, glacier, memoryhog, cpuhog, core, et ainsi de suite.

Ensuite, exécutez all 'quick' tests ou run everything except 'memoryhog' tests, la configuration de votre liste blanche / liste noire de base

Mise en œuvre

Je mis en œuvre ce en 2 parties:

  1. Tout d'abord ajouter des étiquettes à des tests (via une coutume décorateur de classe @testlabel)
  2. personnalisé pour identifier les unittest.TestRunner tests à sauter, et modifier le contenu de testlist avant d'exécuter.

Mise en oeuvre de travail est dans ce point essentiel: https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(un exemple entièrement trop longtemps pour mettre ici)

Le résultat étant ...

$ ./runtests.py --blacklist foo
test_foo (test_things.MyTest2) ... ok
test_bar (test_things.MyTest3) ... ok
test_one (test_things.MyTests1) ... skipped 'label exclusion'
test_two (test_things.MyTests1) ... skipped 'label exclusion'

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

OK (skipped=2)

Tous les tests de classe MyTests1 sont ignorés, car il a l'étiquette foo.

--whitelist fonctionne aussi

Regardez en utilisant un TestRunner dédié, comme py.test, nez ou peut-être même zope.testing. Elles ont toutes les options de ligne de commande pour la sélection des tests.

Regardez par exemple que le nez: https://pypi.python.org/pypi /nose/1.3.0

J'ai essayé @ réponse de Slott:

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Mais cela m'a donné l'erreur suivante:

Traceback (most recent call last):
  File "functional_tests.py", line 178, in <module>
    unittest.TextTestRunner().run(suite)
  File "/usr/lib/python2.7/unittest/runner.py", line 151, in run
    test(result)
  File "/usr/lib/python2.7/unittest/case.py", line 188, in __init__
    testMethod = getattr(self, methodName)
TypeError: getattr(): attribute name must be string

Ce qui suit a fonctionné pour moi:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)

Je l'ai trouvé une autre façon de sélectionner le test_ * méthodes que je veux seulement courir en ajoutant un attribut à leur disposition. Vous utilisez essentiellement un métaclasse pour décorer les appelables à l'intérieur de la classe TestCase qui ont l'attribut StepDebug avec un décorateur unittest.skip. Plus d'info sur

sauter tous les tests unitaires, mais un en Python en utilisant les décorateurs et les métaclasses

Je ne sais pas si elle est une meilleure solution que celles ci-dessus, je suis juste comme une fournirai option.

n'avez pas trouvé une belle façon de le faire avant, donc le partage ici.

Objectif: Obtenir un ensemble de fichiers de test ensemble afin qu'ils puissent être gérés comme une unité, mais nous pouvons toujours sélectionner l'un d'eux à exécuter par lui-même.

Problème: la méthode discover ne permet pas une sélection facile d'un seul cas de test pour exécuter

.

Conception: voir ci-dessous. Cette aplanit l'espace de noms afin peut sélectionner par TestCase nom de la classe, et laisser tomber le préfixe « de tests1.test_core »:

./run-tests TestCore.test_fmap

code

  test_module_names = [
    'tests1.test_core',
    'tests2.test_other',
    'tests3.test_foo',
    ]

  loader = unittest.defaultTestLoader
  if args:
    alltests = unittest.TestSuite()
    for a in args:
      for m in test_module_names:
        try:
          alltests.addTest( loader.loadTestsFromName( m+'.'+a ) )
        except AttributeError as e:
          continue
  else:
    alltests = loader.loadTestsFromNames( test_module_names )

  runner = unittest.TextTestRunner( verbosity = opt.verbose )
  runner.run( alltests )

Ceci est la seule chose qui a fonctionné pour moi.

if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

Quand je l'ai appelé si je devais passer au nom du nom de classe et test. Un peu gênant car je n'ai pas combinaison de classe et le nom de test mémorisé.

python ./tests.py class_Name.test_30311

Suppression du nom de classe et le nom de test exécute tous les tests dans votre dossier. Je trouve cela beaucoup plus facile à traiter alors intégré dans la méthode que je ne change pas vraiment ma commande sur la CLI. Il suffit d'ajouter le paramètre.

Profitez, Keith

J'ai créé un décorateur qui permet de marquer des tests comme des tests lents et de les sauter en utilisant une variable d'environnement

from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

Maintenant, vous pouvez marquer vos tests aussi lent comme ceci:

@slow_test
def test_my_funky_thing():
    perform_test()

Et passer des tests lents en définissant la SKIP_SLOW_TESTS variable d'environnement:

SKIP_SLOW_TESTS=1 python -m unittest
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top