Run tests in parallel with pytest

When we have a lot of test cases in our framework, it takes a lot of time to execute all the test cases.

Instead of running tests sequentially, or one after the other, parallel testing allows us to execute multiple tests at the same and decrease the time taken. Parallel testing helps to faster testing and has a quicker turn around in release process.

To run tests in parallel using pytest, we need pytest-xdist plugin which extends pytest with some unique test execution modes.

We will show you an example on how to use xdist-plugin to run pytests in parallel.

Let's first install pytest-xdist plug-in by running below command :-

pip install pytest-xdist

That’s it. Now we can execute the test in Parallel.

Just navigate to the tests folder and run the command :-

pytest -n=2

Here the alphabet 'n' in the above command indicates the number of browsers you wanted to open and run the test cases in parallel.

There are many other options available in xdist-plugin documentation

Let’s look at the example below :-

First create conftest.py like below : -

import pytest
from selenium import webdriver


@pytest.fixture(scope="session")
def setup(request):
    print("initiating chrome driver")
    driver = webdriver.Chrome(r'C:/Users/HarryDev/Downloads/chromedriver2.43/chromedriver.exe')
    session = request.node
    for item in session.items:
        cls = item.getparent(pytest.Class)
        setattr(cls.obj, "driver", driver)
    driver.get("http://seleniumeasy.com/test")
    driver.maximize_window()

    yield driver
    driver.close()

Now create a test file test_example1.py and add below code :-

import pytest

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


@pytest.mark.usefixtures("setup")
class TestExampleOne:
    def test_title(self):
         assert "Selenium Easy" in self.driver.title

    def test_content_text(self):
        print("Verify content on the page")
        centerText = self.driver.find_element_by_css_selector('.tab-content .text-center').text
        assert "WELCOME TO SELENIUM EASY DEMO" == centerText

    def test_bootstrap_bar(self):
        print("Lets try with another example")
        mainMenu = self.driver.find_element_by_xpath("//li/a[contains(text(), 'Progress Bars')]")
        mainMenu.click()

        subMenu = self.driver.find_element_by_xpath("//li/a[contains(text(), 'Bootstrap Progress bar')]")
        subMenu.click()

        btnDownload = self.driver.find_element_by_id("cricle-btn")
        btnDownload.click()

        WebDriverWait(self.driver, 50).until(EC.text_to_be_present_in_element_value((By.ID, 'cricleinput'), "105"))

        elemValue = self.driver.find_element_by_id("cricleinput")
        elemVAttributealue = elemValue.get_attribute('value')
        assert elemVAttributealue == "105"

    def test_one(self):
        x = "this"
        assert 'h' in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, 'check')

    def test_three(self):
        x = "welcome"
        assert hasattr(x, 'test')

Now create another test file test_example2.py and add below code :-

import pytest
import time

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


@pytest.mark.usefixtures("setup")
class TestExampleTwo:

    def test_InputForm(self):

        print("Another example")
        mainMenu = self.driver.find_element_by_xpath("//li/a[contains(text(), 'Input Forms')]")
        mainMenu.click()

        subMenu = self.driver.find_element_by_xpath("//li/a[contains(text(), 'Simple Form Demo')]")
        subMenu.click()

        #Finding "Single input form" input text field by id. And sending keys(entering data) in it.
        eleUserMessage = self.driver.find_element_by_id("user-message")
        eleUserMessage.clear()
        eleUserMessage.send_keys("Test Python")

        #Finding "Show Your Message" button element by css selector using both id and class name. And clicking it.
        eleShowMsgBtn=self.driver.find_element_by_css_selector('#get-input > .btn')
        eleShowMsgBtn.click()

        #Checking whether the input text and output text are same using assertion.
        WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.ID, 'display')))
        eleYourMsg=self.driver.find_element_by_id("display")
        assert "Test Python" in eleYourMsg.text

    def test_funcfast(self):
        time.sleep(0.1)

    def test_funcslow1(self):
        time.sleep(0.2)

    def test_funcslow2(self):
        time.sleep(0.3)

Note:- To make results look better, We have added selenium webdriver tests and also few sample tests. We are sharing the single webdriver session that we create using pytest fixtures. In this example, we are sharing webdriver session in multiple classes.

Now execute the tests. In PyTest, to execute tests just type pytest in the terminal in the project root folder / tests folder. This will execute all tests.

pytest -s -v -n=2

When you have several test classes and/or modules in test suite, we have to reuse driver over and over again. We have taken care of this by using pytest fixtures.

After the execution of above program, you will see the following report :-

Pytest parallel execution

Pytest parallel execution results

PyTest offers a great flexibility in writing selenium tests using fixtures.

A fixture has 4 scopes module, class, session and function ( function scope is the default value). In pytest selenium framework, mainly we use scope=session and scope=class. We have discussed fixtures in detail earlier with selenium webdriver example using fixtures

In the above example, we have used scope=session, using this, the fixture will be created only once per test session and shared across several tests.

Selenium Tutorials: 

Add new comment