Vadim  Kovrizhkin
Vadim Kovrizhkin

Reputation: 1781

How can I execute in parallel Selenium Python tests with unittest

For example I have two tests:

class Test(unittest.TestCase):
    def setUp(self):
    self.driver = webdriver.Firefox()
    self.driver.get("http://google.com")

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

def test_selenium_1(self):
    search_field = self.driver.find_element_by_id("lst-ib")
    search_field.send_keys("Test 1. Number 1")
    search_field.submit()
    time.sleep(2)

def test_selenium_2(self):
    search_field = self.driver.find_element_by_id("lst-ib")
    search_field.send_keys("Test 1. Number 2")
    search_field.submit()
    time.sleep(2)

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

How can I execute these two tests in parallel with concurrent.futures.Executor?

Is it possible?

Upvotes: 1

Views: 1287

Answers (2)

cptncrnch
cptncrnch

Reputation: 145

I rewrote @vadim-kovrizhkin's solution as a separate runner file that one can use to add separate test cases (importing each test case from their respective py files). This will run setUp, the unit tests in your test cases concurrently, and then tearDown.

from unittest import TestLoader, TestSuite, TextTestRunner
from concurrent.futures import ThreadPoolExecutor
from YourTestFolder.SubFolder.test_foo import Test_Foo

def suite():
    loader = TestLoader()
    suite = TestSuite(loader.loadTestsFromTestCase(Test_Foo))
    return suite

if __name__ == "__main__":

    suite = suite()
    with ThreadPoolExecutor() as executor:
        list_of_suites = list(suite)
        for test in range(len(list_of_suites)):
            test_name = str(list_of_suites[test])
            executor.submit(TextTestRunner().run, list_of_suites[test])

Thanks again to Vadim for their elegant solution!

Upvotes: 0

Vadim  Kovrizhkin
Vadim Kovrizhkin

Reputation: 1781

I created Runner for these purposes.

And now I can execute tests in parallel by modules, classes and methods.

import unittest
from concurrent.futures import ThreadPoolExecutor

class Runner():

    def parallel_execution(self, *name, options='by_module'):

        """
        name - name of the class with tests or module with classes that contain tests
        modules - name of the module with tests or with class that contains tests
        options:
            by_method - gather all tests methods in the class/classes and execute in parallel
            by_module - gather all tests from modules in parallel
            by_class - will execute all classes (with tests) in parallel
        """

        suite = unittest.TestSuite()

        if (options=='by_method'):
            for object in name:
                for method in dir(object):
                    if (method.startswith('test')):
                        suite.addTest(object(method))
        elif (options=='by_class'):
            for object in name:
                suite.addTest(unittest.TestLoader().loadTestsFromTestCase(object))

        elif (options=='by_module'):
            for module in name:
                suite.addTest(unittest.TestLoader().loadTestsFromModule(module))
        else:
            raise ValueError("Parameter 'options' is incorrect."
                             "Available options: 'by_method', 'by_class', 'by_module'")

        with ThreadPoolExecutor(max_workers=10) as executor:
            list_of_suites = list(suite)
            for test in range(len(list_of_suites)):
                test_name = str(list_of_suites[test])
                executor.submit(unittest.TextTestRunner().run, list_of_suites[test])

EXAMPLES:

#by_methods
Runner().parallel_execution(Test1.Test1, Test2.Test22, Test2.Test33, options='by_method')

#by_class
Runner().parallel_execution(Test1.Test1, Test2.Test22, Test2.Test33, options='by_class')

#by_modules
Runner().parallel_execution(Test1, Test2)

Upvotes: 3

Related Questions