2013-09-30 14 views
7

Sto cercando di creare un quadro di unit test su misura per sotto-classificare la classe unittest.TestCase ma sembrano fare un errore quando si tratta con il metodo __init__.sovraccarico unittest.TestCase in python

Non riesco a capire perché il costruttore di ComplexTest non venga richiamato prima di quello in BasicTest e l'eccezione sembra essere correlata ai miei costruttori.

Sono abbastanza nuovo a Python in modo che qualsiasi aiuto su come risolvere questo problema specifico o architetture alternative al mio caso d'uso sarà il benvenuto.

Grazie!

1) test_framework.py

import unittest 

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(unittest.TestCase, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('BasicTest.setUp') 
     super(unittest.TestCase, self).tearDown() 

    def tearDown(self): 
     print('BasicTest.tearDown') 
     super(unittest.TestCase, self).tearDown() 


class ComplexTest(BasicTest): 
    def __init__(self, *args, **kwargs): 
     print('ComplexTest.__init__') 
     super(BasicTest, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('ComplexTest.setUp') 
     super(BasicTest, self).tearDown() 

    def tearDown(self): 
     print('ComplexTest.tearDown') 
     super(BasicTest, self).tearDown() 

2) test.py

import unittest 
import test_framework 

class TestValueFunctions(test_framework.ComplexTest): 
    def __init__(self, *args, **kwargs): 
     print('TestValueFunctions.__init__') 
     super(test_framework.ComplexTest, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('TestValueFunctions.setUp') 
     super(test_framework.ComplexTest, self).tearDown() 
     self.value = 4711 

    def tearDown(self): 
     print('TestValueFunctions.tearDown') 
     super(test_framework.ComplexTest, self).tearDown() 

    def test_value(self): 
     print('TestValueFunctions.test_value') 
     self.assertEqual(self.value, 4711) 

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

3) quando ora cercando di eseguire questo, vedo il seguente stack

TestValueFunctions.__init__ 
BasicTest.__init__ 
Traceback (most recent call last): 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 23, in <module> 
    unittest.main() 
    File "C:\Python27\lib\unittest\main.py", line 94, in __init__ 
    self.parseArgs(argv) 
    File "C:\Python27\lib\unittest\main.py", line 149, in parseArgs 
    self.createTests() 
    File "C:\Python27\lib\unittest\main.py", line 155, in createTests 
    self.test = self.testLoader.loadTestsFromModule(self.module) 
    File "C:\Python27\lib\unittest\loader.py", line 65, in loadTestsFromModule 
    tests.append(self.loadTestsFromTestCase(obj)) 
    File "C:\Python27\lib\unittest\loader.py", line 56, in loadTestsFromTestCase 
    loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 7, in __init__ 
    super(test_framework.ComplexTest, self).__init__(*args, **kwargs) 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test_framework.py", line 6, in __init__ 
    super(unittest.TestCase, self).__init__(*args, **kwargs) 
TypeError: object.__init__() takes no parameters 
+0

Uno dei grandi vantaggi di 'super' è che non si deve ** esplicitamente dichiarare la superclasse. Come vedi negli errori, stai chiamando 'object .__ init__' invece di' TestCase .__ init__' con quel codice. – Bakuriu

+1

Solo in Python 3 puoi omettere l'argomento di classe a 'super'. – chepner

risposta

17

Infatti il ​​metodo init è sbagliato.

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(unittest.TestCase, self).__init__(*args, **kwargs) 

dovrebbe essere:

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(BasicTest, self).__init__(*args, **kwargs) 

Questo chiamerà __init__ sulla classe madre di BasicTest, che è TestCase. Lo stesso vale per setUp e tearDown:

class BasicTest(unittest.TestCase): 
    ... 
    def setUp(self): 
     print('BasicTest.setUp') 
     super(BasicTest, self).setUp() 
+0

eccellente: Ho sembra di aver capito male super, ma ora funziona come un fascino. Grazie! – doberkofler

+0

l'ultima riga di esempio di setUp dovrebbe essere: 'super (BasicTest, self) .setUp()'. In questo momento chiamerà il metodo genitore tearDown, che non è logico.Lo stesso per gli esempi di codice domanda. – manelvf

0

Ah super! Chissà perché fa qualcosa. Se si smette di utilizzare nella prova e invece chiamare esplicitamente la classe genitore che si desidera, in questo modo:

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     unittest.TestCase.__init__(self, *args, **kwargs) 

vi ritroverete con l'uscita di seguito:

TestValueFunctions.__init__ 
ComplexTest.__init__ 
TestValueFunctions.setUp 
ComplexTest.setUp 
TestValueFunctions.test_value 
TestValueFunctions.tearDown 
ComplexTest.tearDown 
. 
---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK 

See: Python's Super is nifty, but you can't use it

+0

Questo è vero solo se non ti aspetti che faccia parte dell'ereditarietà multipla; in caso contrario, ciò causerà la rottura di cose e potenzialmente un comportamento imprevisto. –

+0

Non rompe le cose. Soprattutto perché 'unittest.TestCase' non usa super. È un caso di chiamare esplicitamente il codice che si desidera nell'ordine in cui si desidera chiamarlo. – aychedee

+0

Non è vero, se si dispone di questa e un'altra classe che le sottoclassi 'unittest.TestCase' sia come genitori scalo a questa classe, o di un altro modo tale che questo finisce per prima nella MRO di un altro metodo, sarà problematico. Forse meno in questo caso particolare, ma più in generale non è una buona scelta (soprattutto se si tratta di una sottoclasse diretta dell'oggetto) –