WebDriver tests in PyTest using Fixtures and conftest.py

Fixtures are a powerful feature of PyTest. Fixtures help us to setup some pre-conditions like setup a database connection / get test data from files etc that should run before any tests are executed. Earlier we have seen Fixtures and Scope of fixtures, In this article, will focus more on using fixtures with conftest.py

We can put fixtures into individual test files, if we want the fixture to be only used by a single test file. But to share fixtures among multiple test files, we need to use conftest.py file so that tests from multiple test classes/modules in the directory can access the fixture function.

When fixture function is called, it will run the code in the function from the beginning until it hits yield statement which serves as the "setUp" code and the code after the yield statement serves as the "tearDown" code. The code after the yield is guaranteed to run regardless of what happens during the tests.

In order to share fixtures across multiple tests, py.test suggests to define fixtures in one single conftest.py file.

It is usually a good idea to keep your conftest.py file in the top level test or project root directory.

Before proceeding, You'll need to be sure you have downloaded selenium bindings for python.

Open command prompt and install selenium by typing "pip install selenium" and press enter. You can find more details here - Get started using Selenium with Python

Example: - Let's see how this works

We will create conftest.py file and add below code to a conftest.py file at the root of your tests' directory : -

import pytest
from selenium import webdriver


@pytest.fixture(scope="class")
def setup(request):
    print("initiating chrome driver")
    driver = webdriver.Chrome("chrome driver path") #if not added in PATH
    driver.get("http://seleniumeasy.com/test")
    driver.maximize_window()
    request.cls.driver = driver

    yield driver
    driver.close()

Let us create two classes "test_exampleOne.py" and "test_exampleTwo.py" and decorate with @pytest.mark.usefixtures("setup")

class - test_exampleOne.py

import pytest
from selenium import webdriver
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"

class - test_exampleTwo.py

import pytest


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

    def test_simpleInputForm(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.
        eleYourMsg=self.driver.find_element_by_id("display")
        assert "Test Python" in eleYourMsg.text

The above two classes "test_exampleOne.py" and "test_exampleTwo" are decorated with @pytest.mark.usefixtures("setup").

Applying "@pytest.mark.usefixtures" to the class is same as applying a fixture to every test methods in the class. Since the fixture "setup" has a scope defined as "class", webdriver will be initialized only once per each class.

If you observe, In fixture, we have set the driver attribute via "request.cls.driver = driver", So that test classes can access the webdriver instance with self.driver.

Run your program using pytest -s and if everything goes well, the output looks like below :-
Below is the output image :-

pytest fixture conftest selenium

We hope that this article helps you to understand pytest fixtures and conftest.py. It's very easy to get started with using it, and it can handle most of what you need in automation testing. Give it a try !!!

Selenium Tutorials: 

Add new comment

CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.