6

I have this plain vanilla unit test, which works as expected, as long I leave out the constructor.

import sys
import unittest

class Instance_test(unittest.TestCase):

  def __init__(self):
     super(Instance_test, self).__init__()
     self.attribute = "new"

  def test_something(self):
     pass

  def test_other(self):
     self.assertTrue(True)
     pass

  def setUp(self):
     pass

  def tearDown(self):
     pass

def suite():
  return unittest.makeSuite(Instance_test, "test")

def main():
  runner = unittest.TextTestRunner(sys.stdout)
  runner.run(suite())

if __name__ == "__main__":
   main()

With the constructor in place in get this backtrace:


 Traceback (most recent call last):
   File "f:\gt\check.py", line 31, in  main()
   File "f:\gt\check.py", line 28, in main
      runner.run(suite())
   File "f:\gt\check.py", line 24, in suite
    return unittest.makeSuite(Instance_test, "test")
  File "C:\Python34\lib\unittest\loader.py", line 374, in makeSuite
    testCaseClass)
  File "C:\Python34\lib\unittest\loader.py", line 70, in loadTestsFromTestCase
    loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
  File "C:\Python34\lib\unittest\suite.py", line 24, in __init__
    self.addTests(tests)
  File "C:\Python34\lib\unittest\suite.py", line 60, in addTests
    for test in tests:
 TypeError: __init__() takes 1 positional argument but 2 were given

What's wrong and how else could I have a central attribute to be shared by different test_xxx methods?

guidot
  • 5,095
  • 2
  • 25
  • 37
  • 3
    You're subclassing a method with arguments that you aren't dealing with. You need to make `__init__` accept arbitrary arguments (usually `*args, **kwargs`) and pass them to the superclass implementation. – jonrsharpe Feb 05 '16 at 17:13
  • 1
    @jonrsharpe: Yesss, thank you – guidot Feb 05 '16 at 17:15

3 Answers3

7

I would use unittest.TestCase's setUp() and tearDown() methods instead of init. Just do the same thing you're doing except use the setUp method.

2achary
  • 642
  • 2
  • 6
  • 9
6

It is happening because __init__ takes more than one arguments, you forgot to provide args and kwargs as arguments. It should have been like this -

class Instance_test(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        super(Instance_test, self).__init__(*args, **kwargs)
        self.attribute = "new"

Besides why are you overriding __init__ anyway (as 2achary suggested) when setUp method is exactly meant for this purpose.

class Instance_test(unittest.TestCase):

    def setUp(self):
        self.attribute = 'new'
hspandher
  • 15,934
  • 2
  • 32
  • 45
  • 1
    There is a difference between init and setUp(). init is called only once per class while setUp is called before every test case run – Kartikeyan Gupta Jan 20 '22 at 09:43
0

Just add an argument named methodName to your own __init__ method and you should be good to go:

class Instance_test(unittest.TestCase):

  def __init__(self, methodName='runTest'):
     super(Instance_test, self).__init__(methodName=methodName)
     self.attribute = "new"

  ...

The base TestCase.__init__ signature is as follows:

class TestCase(object):

    def __init__(self, methodName='runTest'):
        ...

As you can see, it takes an additional methodName argument, and there is no constructor without it, hence the failure you encountered.

Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126