337 votes

Comment générer des tests unitaires dynamiques (paramétrés) en python?

J'ai une sorte de données de test et je souhaite créer un test unitaire pour chaque élément. Ma première idée était de le faire comme ceci:

 import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequence(unittest.TestCase):
    def testsample(self):
        for name, a,b in l:
            print "test", name
            self.assertEqual(a,b)

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

L'inconvénient est qu'il gère toutes les données en un seul test. Je voudrais générer un test pour chaque élément à la volée. Aucune suggestion?

264voto

mojo Points 1473

J'utilise quelque chose comme ça:

 import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequense(unittest.TestCase):
    pass

def test_generator(a, b):
    def test(self):
        self.assertEqual(a,b)
    return test

if __name__ == '__main__':
    for t in l:
        test_name = 'test_%s' % t[0]
        test = test_generator(t[1], t[2])
        setattr(TestSequense, test_name, test)
    unittest.main()
 

229voto

codeape Points 38576

Le cadre de test de nez prend en charge cela .

Exemple (le code ci-dessous représente l'intégralité du contenu du fichier contenant le test):

 param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')]

def test_generator():
    for params in param_list:
        yield check_em, params[0], params[1]

def check_em(a, b):
    assert a == b
 

La sortie de la commande nosetests:

 > nosetests -v
testgen.test_generator('a', 'a') ... ok
testgen.test_generator('a', 'b') ... FAIL
testgen.test_generator('b', 'b') ... ok

======================================================================
FAIL: testgen.test_generator('a', 'b')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.5/site-packages/nose-0.10.1-py2.5.egg/nose/case.py", line 203, in runTest
    self.test(*self.arg)
  File "testgen.py", line 7, in check_em
    assert a == b
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.006s

FAILED (failures=1)
 

88voto

Guy Points 199

Cela peut être résolu de manière élégante en utilisant des métaclasses:

 import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequenceMeta(type):
    def __new__(mcs, name, bases, dict):

        def gen_test(a, b):
            def test(self):
                self.assertEqual(a, b)
            return test

        for tname, a, b in l:
            test_name = "test_%s" % tname
            dict[test_name] = gen_test(a,b)
        return type.__new__(mcs, name, bases, dict)

class TestSequence(unittest.TestCase):
    __metaclass__ = TestSequenceMeta

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

43voto

Javier Points 278

load_tests est un peu connu mécanisme de créer dynamiquement une suite de tests. Avec elle, vous pouvez facilement créer des tests paramétrés.

Par exemple:

import unittest

class GeneralTestCase(unittest.TestCase)
    def __init(self, methodName, param1, param2):
        super(GeneralTestCase, self).__init__(methodName)

        self.param1 = param1
        self.param2 = param2

    def runTest(self):
        pass  # Test that depends on param 1 and 2.


def load_tests(loader, tests, pattern):
    test_cases = unittest.TestSuite()
    for p1, p2 in [(1, 2), (3, 4)]:
        test_cases.addTest(GeneralTestCase('runTest', p1, p2))
    return test_cases

Ce code s'exécutera tous les cas de tests dans la suite de tests retourné par load_tests. Pas d'autres tests sont automatiquement gérées par le mécanisme de découverte.

Alternativement, vous pouvez également utiliser l'héritage comme indiqué dans ce billet: http://bugs.python.org/msg151444

6voto

bignose Points 6573

Vous auriez intérêt à essayer la bibliothèque TestScenarios .

testscenarios fournit une injection de dépendance propre pour les tests de style python unittest. Cela peut être utilisé pour le test d'interface (tester de nombreuses implémentations via une seule suite de tests) ou pour l'injection de dépendances classique (fournir des tests avec des dépendances externes au code de test lui-même, permettant des tests faciles dans différentes situations).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X