overloading unittest.testcase in python

doberkofler picture doberkofler · Sep 30, 2013 · Viewed 17k times · Source

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

Answer

GL770 picture GL770 · Sep 30, 2013

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()