1

I am writing unit tests and have the following structure:

class TestSuite(unittest.TestCase, HelperClass):
  @classmethod
  def setUpClass(cls):
    # I want to use methods from HelperClass here, but get errors
    # I have tried cls.method_name() and self.method_name()

  def setUp(self):
    self.method_name() # methods from HelperClass work here
...

As noted in my comments, I'd like to use some validation methods from HelperClass in my setUpClass method, but if I try to call with cls.method_name(), I get TypeError: method_name() missing 1 required positional argument: 'self', but if I use self.method_name(), I get NameError: name 'self' is not defined.

This is probably something pretty basic, but I'm just not sure the correct search term I'm supposed to use to find the answer. The unittest documentation on setUpClass doesn't get into it either, unfortunately.

Danny
  • 470
  • 1
  • 4
  • 21
  • 1
    `setupClass` doesn't take an *instance* of `TestSuite`, just `TestSuite` itself, so you can't call instance methods. – chepner Mar 27 '20 at 12:37
  • 1
    `setUp`, on the other hand, *does* take an instance of `TestSuite`. – chepner Mar 27 '20 at 12:39
  • So I have a number of actions I need to perform from HelperClass, just once before all tests in TestSuite. Is there no way to access the methods of HelperClass to have them run just once? I don't want or need them to run for each test, as they would in setUp() – Danny Mar 27 '20 at 12:41
  • 1
    The actions you want require an instance of `HelperClass` (which an instance of `TestSuite` is), but when `setUpClass` is called, you simply do not have such an instance. Without knowing exactly what kind of setup you want to perform, it's difficult to suggest how to redesign your class. – chepner Mar 27 '20 at 12:44

2 Answers2

2

The problem is that in setUpClass, you simply don't have an instance of TestSuite on which you can call instance methods defined by HelperClass. The test runner does something along the lines of

TestSuite.setUpClass()

t = TestSuite(...)

t.setUp()
t.test_foo()
t.tearDown()

t.setUp()
t.test_bar()
t.tearDown()

setUpClass is called once, without an instance of TestSuite, before you create the single instance that will be used to call each test defined in the class. The setUp and tearDown methods are called before and after, respectively, each test.

What you might want is to override TestSuite.__init__, which is called once per instance, rather than before each test method is called.

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.method_name()
chepner
  • 497,756
  • 71
  • 530
  • 681
1

I don't know if it was the right solution, but I found a way to do this that was ultimately pretty obvious.

class TestSuite(unittest.TestCase, HelperClass):
  @classmethod
  def setUpClass(cls):
    hc = HelperClass()
    hc.method_name()

  def setUp(self):
    self.method_name() # methods from HelperClass work here
...

In retrospect, I should have seen this right away, haha. Figured I'd share for someone also searching around on this someday.

Danny
  • 470
  • 1
  • 4
  • 21