jononomo jononomo - 26 days ago 11
Python Question

Python unittest - setUpClass() is giving me trouble - why can't I inherit like this?

I have unittest code like the following:

import unittest

class MyUnitTest(unittest.TestCase):
def setUpClass(self):
do_something_expensive_for_all_sets_of_tests()

class MyFirstSetOfTests(MyUnitTest):
def setUpClass(self):
super(MyFirstSetOfTests, self).setUpClass()
do_something_expensive_for_just_these_first_tests()

def test_one(self):
...

def test_two(self):
...

class MySecondSetOfTests(MyUnitTest):
def setUpClass(self):
super(MySecondSetOfTests, self).setUpClass()
do_something_expensive_for_just_these_second_tests()

def test_one(self):
...

def test_two(self):
...

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


When I try to run this code, I get an error like this:

======================================================================
ERROR: setUpClass (__main__.MyFirstSetOfTests)
----------------------------------------------------------------------
TypeError: unbound method setUpClass() must be called with MyFirstSetOfTests instance as first argument (got nothing instead)

----------------------------------------------------------------------

Answer Source

setUpClass must be a class method. From the documentation:

A class method called before tests in an individual class run. setUpClass is called with the class as the only argument and must be decorated as a classmethod():

@classmethod def setUpClass(cls): ...

See Class and Module Fixtures for more details.

Your version is missing the @classmethod decorator:

class MyUnitTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        do_something_expensive_for_all_sets_of_tests()

class MyFirstSetOfTests(MyUnitTest):
    @classmethod
    def setUpClass(cls):
        super(MyFirstSetOfTests, cls).setUpClass()
        do_something_expensive_for_just_these_first_tests()

The error is thrown because MyFirstSetOfTests.setUpClass() is called on the class, not on an instance, but you didn't mark your method as a classmethod and thus it was not passed in the automatic self argument.