Unittest + Selenium - __init__() takes 1 positional argument but 2 were given

Viewed 3322

I'm working with unittest and selenium for the first time but thats also my first bigger code in python. I found some answers for this problem but there was no explaination for classes with __ init __ inheritance and method super().__ init __()

TL;DR I have classes that inherits one by one. The first class StartInstance that creates chrome instance inherits from unittest.TestCase and the problem is with inheritance and super().init() in other classes, becouse when i remove it test normaly starts

All looks like:

class StartInstance(unittest.TestCase):
    @classmethod
    def setUpClass(cls): pass

class A(StartInstance):
    def __init__(self):
        super().__init__() adding variables etc to init

class B(A):
    def __init__(self): 
        super().__init__() adding variables etc to init

class C(A):
    def __init__(self):
        super().__init__() adding variables etc to init

class PrepareTests(B, C, D):
    def all tests(self):
        self.tests_B
        self.tests_C
        self.tests_D

 class Tests(PrepareTests):
    def test_click:
        click()
        all_tests()


 #and finally somewhere a test runner
 suite = loader.loadTestsFromTestCase(Tests)
 runner.run(suite())

#when i run this i get this error and it only raises when i 
add classes with their own init
#heh TL;DR almost as long as normal text sorry :(

ALL:

FULL ERROR MESSAGE:

Traceback (most recent call last):
 File "xyz\main_test.py", line 24, 
 in <module>
   runner.run(suite())
  File "xyz\main_test.py", line 11, 
in suite
   about_us = loader.loadTestsFromTestCase(AboutUs)
 File 
"xyz\Python36\lib\unittest\loader.py", line 92, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
 File "xyz\Python36\lib\unittest\suite.py", line 24, in __init__
  self.addTests(tests)
 File "xyz\Python36\lib\unittest\suite.py", line 57, in addTests
   for test in tests:
 TypeError: __init__() takes 1 positional argument but 2 were given

Thats my code:

I have a settings.py file with variables in dict of dicts accessed by settings.xyz["layer1"]["KEY"]

setup.py - setup class for selenium

class StartInstance(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome()
        cls.driver.get(settings.URLS['MAIN_URL'])
        cls.driver.implicitly_wait(2)
        cls.driver.maximize_window()

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

main_tests_config.py - next layer - now very basic configs

class MainTestConfig(StartInstance):
    def __init__(self):
        super().__init__()
        self.language = settings.TEST_LANGUAGE
        self.currency = settings.TEST_CURRENCY

header.py (got few more files like this) - next layer translates code from config.py to class variables, inherits from previous classes becouse it needs global language

class HeaderPath(MainTestConfig):
    def __init__(self):
        super().__init__()
        self.logo_path = settings.PAGE_PATHS["HEADER"]["LOGO"]
        self.business_path = settings.PAGE_PATHS["HEADER"]["BUSINESS"]

class HeaderText(MainTestConfig):
    def __init__(self):
        super().__init__()
        self.business_text = settings.PAGE_CONTENT[self.language]["HEADER"]["BUSINESS"]
        self.cart_text = settings.PAGE_CONTENT[self.language]["HEADER"]["CART"]

header_tests.py - next layer, inherits variables(HeadetText, HeaderPath, Urls(class Urls it is class with page urls variables)), language(from MainTestConfig), and selenium driver (from first class StartInstance), example build of class

class HeaderStaticTest(HeaderText, HeaderPath, Urls):
    def header_static(self):
        self.logo_display()
        self.method2()
        # etc..

    def logo_display(self):
        self.driver.find_element_by_xpath(self.logo_path)
    def self.method2(self):
        pass

static_display.py - next layer, class that inherits all classes with tests like previous one and uses their methods that runs all tests but not as test_

class StaticDisplay(HeaderStaticTest, HorizontalStaticTest, VerticalStaticTest):
    def static_display(self):
        self.header_static()
        self.horizontal_static()
        self.vertical_static()

test_about_us.py - next layer, a normal unittest testcase it inherits only a previous one but in general it inherits all prevous classes that i wrote, now i can test all "static views" on page that dont change when i click on button

class AboutUs(StaticDisplay):
    def test_horizontal_menu_click(self):
        about_us_element = self.driver.find_element_by_id(self.hor_about_path)
        about_us_element.click()
        self.assertIn(
            self.about_url,
            self.driver.current_url
        )

    def test_check_static_after_horizontal(self):
        self.static_display()

(finally) main_cases.py - runner with this error, and it only raises when I add classes with their own init... have no idea how to repair it... please help

def suite():
    loader = unittest.TestLoader()
    about_us = loader.loadTestsFromTestCase(AboutUs)
    return unittest.TestSuite([about_us])

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

As i said there is somewhere problem with this new def __ init __ and super().__ init __() in new classes... where I'm making a mistake?

When i start this test case i get an error:

TypeError: __ init __() takes 1 positional argument but 2 were given Full error message above, probably it is needed

Can someone help me please?

2 Answers

TestCase instances take an optional keyword argument methodName; I'm guessing the unittest module passes this explicitly behind the scenes at some point. Typically when I'm subclassing classes I didn't make myself I'll use this pattern; this should fix your problem:

class SubClass(SupClass):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

Especially when you're not passing any arguments to your __init__ method, passing through the arguments in this manner is a good way to avoid the error you're getting. If you do want to pass something custom to your __init__ method, you can do something like this:

class SubClass(SupClass):
    def __init__(self, myarg, *args, **kwargs):
       super().__init__(*args, **kwargs)
       # do something with your custom argument

Ok, I found the problem... It is something else than you wrote the solution that you wrote is good too and I also used It in my code.

Problem from my question was here:

suite = loader.loadTestsFromTestCase(Tests)
runner.run(suite())

I should change to:

something = Tests
suite = loader.loadTestsFromTestCase(something)
runner.run(suite())

BUT another thing is that I had to rebuild it completly to work properly At start: inheritance __ init __ from previous class with super was stupid becouse I didn't have acces to the class before... so I couldn't access my variables. So I've changed:

class SubClass(SupClass):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

with:

class SubClass(SupClass):
    def __init__(self, *args, **kwargs):
        super(SubClass, self).setUpClass(*args, **kwargs)

Then I understood that __ init __ inheritance from unittest.TestCase is impossible. To imagine what happened...

My new way to start test cases:

something = Tests 

it was creating a new error... that said i have to use Tests() but when I used this form I got and previous error so both ways was bad. So I just created class with variables, but with no __ init __ and no super()

class Something(StartInstance):
    a = thing1
    b = thing2
    c = thing3

I'm writing this becouse maybe someone in future will try to use __ init __ with unittest... It doesn't work... or I just didn't find the solution, but I'm new :P

Related