2010-11-30 4 views
9

J'ai plusieurs classes qui partagent des invariants et ont une interface commune, et je voudrais lancer automatiquement le même test pour chacune d'entre elles. Par exemple, supposons que j'ai plusieurs classes qui implémentent des approches différentes pour partitionner un ensemble de données. L'invariant commun ici serait que, pour toutes ces classes, l'union sur toutes les partitions devrait être égale à l'ensemble de données original.Comment exécuter le même test-case pour différentes classes?

Ce que j'ai actuellement ressemble à quelque chose comme ceci:

class PartitionerInvariantsTests(unittest.TestCase): 
    def setUp(self): 
     self.testDataSet = range(100) # create test-data-set 

    def impl(self, partitioner): 
     self.assertEqual(self.testDataSet, 
         chain.from_iterable(partitioner(self.testDataSet)) 

Puis-je ajouter une autre fonction qui appelle impl pour chacune des classes que je veux tester avec une instance de cette classe. Le problème avec ceci devient évident en faisant cela pour plus d'une fonction de test. Supposons que j'ai 5 fonctions de test et 5 classes que je veux tester. Cela ferait 25 fonctions qui sembleraient presque identiques pour invoquer tous les tests.

Une autre approche à laquelle je pensais était de mettre en œuvre le modèle en tant que super-classe, puis de créer une sous-classe pour chacune des classes que je veux tester. Les sous-classes pourraient fournir une fonction pour instancier la classe. Le problème avec cela est que le test-loader par défaut considérerait la classe de base (inutilisable) comme un cas de test valide et essaierait de l'exécuter, ce qui échouerait.

Alors, quelles sont vos suggestions?

P.S .: J'utilise Python 2.6

+1

Unittest essaiera-t-il d'exécuter la classe de base s'il n'hérite pas de 'unittest.TestCase'? – nmichaels

+0

@Nathon: Maintenant que vous le dites, je n'ai pas encore essayé. –

+0

@Nathon, si vous souhaitez poster votre idée comme une réponse, je vais heureusement supprimer le mien. – unutbu

Répondre

11

Vous pouvez utiliser plusieurs héritage.

class PartitionerInvariantsFixture(object): 
    def setUp(self): 
     self.testDataSet = range(100) # create test-data-set 
     super(PartitionInvariantsFixture, self).setUp() 

    def test_partitioner(self): 
     TestCase.assertEqual(self.testDataSet, 
        chain.from_iterable(self.partitioner(self.testDataSet)) 

class MyClassTests(TestCase, PartitionerInvariantsFixture): 
    partitioner = Partitioner 
+0

l'itérateur de chaîne devrait probablement être itéré en utilisant la liste (chaîne ...) – kevpie

+3

pourquoi avons-nous besoin d'appeler super dans la configuration? – dylam

+0

+1 Ma mâchoire est tombée. Il y a des dizaines de questions similaires sur SO (exécutant les mêmes tests sur différents objets avec core unittest), mais c'est certainement la meilleure réponse que j'ai trouvée. Je ne savais même pas (ou je ne me souviens pas) que Python avait plusieurs héritages. –

0

Sous PartitionerInvariantsTests:

class PartitionerInvariantsTests(unittest.TestCase): 
    def test_impl(self): 
     self.assertEqual(self.testDataSet, 
         chain.from_iterable(self.partitioner(self.testDataSet)) 

class PartitionerATests(PartitionerInvariantsTests): 

pour chaque classe Partitioner que vous souhaitez tester. Alors test_impl serait exécuté pour chaque classe de Partitioner, en vertu de l'héritage.

Faisant suite au commentaire de Nathon, vous pouvez empêcher la classe de base d'être testée par l'avoir hérité seulement de object:

import unittest 

class Test(object): 
    def test_impl(self): 
     print('Hi') 

class TestA(Test,unittest.TestCase): 
    pass 

class TestB(Test,unittest.TestCase): 
    pass 

if __name__ == '__main__': 
    unittest.sys.argv.insert(1,'--verbose') 
    unittest.main(argv = unittest.sys.argv)  

cours rendements test.py

test_impl (__main__.TestA) ... Hi 
ok 
test_impl (__main__.TestB) ... Hi 
ok 

---------------------------------------------------------------------- 
Ran 2 tests in 0.000s 

OK 
+2

Oui, mais la classe de base sera également exécutée et échouera. Est-il possible d'exécuter les sous-classes, mais pas la classe de base? –

Questions connexes