Question

I'm trying to create a custom unit test framework by sub-classing the unittest.testcase class but seem to make a mistake when dealing with the __init__ method.

I cannot figure out why the constructor of ComplexTest doesn't get invoked before the one in BasicTest and the exception also seems to be related to my constructors.

I'm pretty new to Python so any help on how to solve this specific problem or alternative architectures to my use case would be most welcome.

Thank you!

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) when now trying to run this, i see the following 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
Was it helpful?

Solution

Indeed your init method is wrong.

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

Should be:

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

This will call __init__ on the mother class of BasicTest, which is TestCase. This is the same for setUp and tearDown:

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

OTHER TIPS

Ah super! Who knows why it does anything. If you stop using it in your test and instead explicitly call the parent class that you want to, like this:

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

You'll end up with the output below:

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top