10

I'm trying to run same test cases with different setUp methods. I've tried using nosetests and parameterized but it seems like it doesn't support parameterizing setUp methods. Here is an example of what I'm trying to do:

...
from nose_parameterized import parameterized

class Example(unittest.TestCase):

    @parameterized.expand(['device1', 'device2'])
    def setUp(self, device):
        desired_caps = {}
        desired_caps['key1'] = device
        desired_caps['key2'] = 'constant value'

    self.driver = webdriver.Remote(url, desired_caps)

    def tearDown(self):
        self.driver.quit()

    def test_app_launch(self):
        # assert something

The error is: TypeError: setUp() takes exactly 2 arguments (1 given).

Is there some other way how to parameterize setUp method? I also looked into nosetests generators but it doesn't seem to be the way to go either.

finspin
  • 4,021
  • 6
  • 38
  • 66

3 Answers3

3

So my approach would be setting up a base test that contains all the tests that the devices have to pass. Then you have to deviceTests that inherit from that baseTest with their own additional setUps which would be device specific.

# this is the base test. Everything that is not specific to the device is set up here. It also contains all the testCases.
import unittest
class deviceTest( unittest.TestCase ):

  def setUp( self ):
    '''
    General setUp here
    '''
    self.desired_caps = {}
    self.desired_caps['key2'] = 'constant value'

  def testWorkflow( self ):
    '''
    Here come the tests that the devices have to pass
    '''

class device1Test( deviceTest ):

  def setUp( self ):
    '''
    device1 specific setup
    '''
    #also run general setUp    
    deviceTest.setUp( self )
    self.desired_caps['key1'] = device
    self.driver = webdriver.Remote(url, desired_caps)


class device2Test( deviceTest ):

  def setUp( self ):
    '''
    device2 specific setup
    '''
    #also run general setUp
    deviceTest.setUp( self )
    self.desired_caps['key1'] = device
    self.driver = webdriver.Remote(url, desired_caps)


if __name__ == '__main__':
  suite = unittest.defaultTestLoader.loadTestsFromTestCase( device1Test )
  suite.addTest( unittest.defaultTestLoader.loadTestsFromTestCase(device2Test ) )
  unittest.TextTestRunner( verbosity = 2 ).run( suite )
Philipp
  • 2,376
  • 5
  • 29
  • 47
  • That could work with a small list of devices but I might have hundreds of devices. Also the list of devices is dynamic (i.e. it's fetched via API before each test run and it might contain different set of devices every time) – finspin Feb 24 '15 at 13:06
  • It worked for me, but I reduced a bit more the specific setup by passing the device name to the method. In the deviceXTest: deviceTest.setup(self, device_name) and then from the parent deviceTest you can use this parameter to create the proper caps and call the driver. – Nan May 02 '20 at 10:06
1

Use a class attribute:

class Example(unittest.TestCase):

    # change before running tests
    device = None

    # make sure device is initialized
    def setUpClass(cls):
        if not cls.device:
            raise Exception("Please initialize device before running tests")

    def setUp(self):
        # consider moving to 'setUpClass'
        desired_caps = {}
        desired_caps['key1'] = Example.device
        desired_caps['key2'] = 'constant value'

    self.driver = webdriver.Remote(url, desired_caps)

    def tearDown(self):
        self.driver.quit()

    def test_app_launch(self):
        # assert something

And run tests for each device separately. You code suggests more things can be moved to the setUpClass method.

Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
  • You mean I should pass a device to the test via command line argument? – finspin Feb 24 '15 at 13:10
  • You could, I'm not sure how you set the tests. My point is that device never changes throughout the tests, so no point in assigning it again and again. One time during class set-up is fine, and the class should test different devices with different runs (assuming all devices must pass all tests). – Reut Sharabani Feb 24 '15 at 13:15
  • Calling the test file multiple times, always with different parameter values is something I'm trying to avoid due to reporting purposes. I need to have just one report containing all devices so that I can include it in the continuous integration workflow. Running these tests with nosetests and parameterized would produce such result only if it played nicely with parameterizing setUp method. – finspin Feb 24 '15 at 16:57
-2

I would just use paramaterized plugin around test, and call out custom setup and teardown methods, passing device parameters to them as part of the test. There is very little magic around using unittest's setUp() and it looks like you are abusing it anyhow.

Oleksiy
  • 6,337
  • 5
  • 41
  • 58