Python & Pytest Framework
Using Selenium with Pytest is a popular combination for testing web applications in Python. Selenium is a web testing library and Pytest is a testing framework.
Pytest Introduction:
Pytest is a testing framework that allows you to write simple unit tests as well as complex functional testing. It is widely used in the Python community for testing applications and libraries. Pytest is known for its simplicity, ease of use, and powerful features.
Pytest Installation:
Install Pycharm IDE to perform automation code for Pytest.
To Install Pytest, you should execute the following command on the Pycharm terminal.
- pip install -U pytest
Once Installation is completed, you can check the Pytest version with the following command on the Pycharm terminal.
- Pytest –version
You need to Install the Selenium package to perform test automation using Pytest with Selenium web driver with the following command on the Pycharm terminal.
- Pytest install -U selenium
Naming Conventions for Pytest Tests
- Python file should create a .py extension.
- File Name starts with test_ or ends with _test.
Example: test_firstProgram.py or firstProgram_test.py
- The class Name starts with “Test”.
Example: TestFirstProgram
- Test Method should start with “test”
Example: test_FirstProgram [underscore is optional]
Pytest Features:
- Fixtures
- Skips tests
- Ordering tests
- Dependent tests
- Grouping tests
- Parallel testing
1. Fixtures:
Pytest fixtures using the @pytest.fixture() marker, allow you to set up and tear down resources needed for your test.
Fixtures can be shared across multiple tests, improving code reuse.
Code:
import pytest
class TestClass:
@pytest.fixture() # we can say decorator, We can give prerequisites using fixtures
def setup(self): # Executes once after the every test Method
print("\nthis is a setup")
yield # Executes once after the every test Method
print(" Closing the browser")
def test_PaymentInDollar(self,setup):
print("this is a SignupByEmail")
assert True == True
def test_PaymentInRuppess(self,setup):
print("this is a SignupByFacebook")
assert True == True
Output:
Command to Execute:
pytest -v -s pytestFeatures\FixtureModules\test_Payment.py
a) v represents: [verbose output]
It is useful for debugging and understanding the test execution flow and It provides more detailed information about the tests being executed.
b) s represents: [Disable output capture]
It disables the output capture, allowing the standard output [stdout] and standard error [stderr] to be printed in the console during the test execution.
- PytestFeatures represents: Directory Name
- FixtureModules represents: SubDirectory Name
- Test_Payment.py represents: Python File Name
2. Skip Tests
In the pytest, you can skip tests using “@pytest.mark.skip” marker. Skipped tests are not executed, allowing you to exclude certain tests from the test run based on specific conditions or requirements.
Code
class TestClass:
def test_LoginByEmail(self):
print("this is a LoginByEmail")
assert 1 == 1
@pytest.mark.skip # using skip marker, you can skip particular tests to run
def test_LoginByFacebook(self):
print("this is a LoginByFacebook")
assert 1 == 1
def test_LoginByTwitter(self):
print("this is a LoginByTwitter")
assert 1 == 1
Output:
Command to execute: pytest -v -s DirectoryName\pythonFileName.py
3. Ordering Test:
You can use the “@pytest.mark.run” marker to control the order of test execution. This marker allows you to assign a unique number to each test, and Pytest will run the tests in ascending order of these numbers.
Firstly you will have to install the “pytest-ordering” package from the Pycharm setting.
Code:
import pytest
class TestOrdering:
@pytest.mark.run(order=3)
def test_MethodA(self):
print("this is a test_MethodA")
@pytest.mark.run(order=1)
def test_MethodB(self):
print("this is a test_MethodB")
@pytest.mark.run(order=2)
def test_MethodC(self):
print("this is a test_MethodC")
Output:
Command to execute: Pytest -v -s DirectoryName\pythonFileName.py
4. Dependent Tests:
In Pytest, you can manage test dependencies using the “pytest-dependency” plugin.
This plugin allows you to express dependencies between tests, ensuring that tests are executed in the correct order based on these dependencies.
Code:
import pytest
class TestClass:
@pytest.mark.dependency()
def test_OpenApp(self):
assert True
@pytest.mark.dependency(depends=['TestClass::test_OpenApp'])
def test_Login(self):
assert True
@pytest.mark.dependency(depends=['TestClass::test_Login','TestClass::test_OpenApp'])
def test_Search(self):
assert True
In this example, the test_Login method is dependent on the test_OpenApp method and the test_Search method is dependent on the test_Login method and test_OpenApp method.
To show dependency, using “@pytest.mark.dependency” decorator is used to mark a test as having dependencies, and the ‘’depends” parameter specifies the dependencies.
- If a test fails, its dependent tests will be marked as “blocked” and won’t be executed.
Circular dependencies are not allowed. If there is a circular dependency, Pytest will raise an error
Output:
Command to execute: Pytest -v -s DirectoryName\pythonFileName.p
5. Grouping Tests
In Pytest, you can define custom markers that represent different groups or categories for your tests and you can run the tests only based on grouping tags. For example, let’s define markers for “smoke” “,sanity” and “regression” tests.
Tests will execute with “@pytest.mark.smoke”, “@pytest.mark.sanity”, and “@pytest.mark.regression” markers Firstly you have to initialize these custom grouping markers in a file [pytest.ini].
Code:
import pytest
class TestGrouping:
@pytest.mark.sanity
def test_LoginByEmail(self):
print("this is a test_MethodA")
assert 1 ==1
@pytest.mark.smoke
@pytest.mark.regression
def test_LoginByFacebook(self):
print("this is a test_MethodB")
assert 1 == 1
@pytest.mark.regression
def test_SignupByEmail(self):
print("this is a test_MethodD")
assert 1 == 1
Output:
Command to execute: Pytest -v -s -m “sanity” DirectoryName\pythonFileName.py
When you run Pytest with the -m option, it will group tests in the test report based on the markers.
Let’s suppose, the command to run is Pytest -v -s -m “sanity” pytestFeatures2\test_Grouping.py, It will execute on sanity group test cases and the rest test cases will be deselected.
You can run multiple group tests using the –
- Pytest -v -s -m “sanity and regression” pytestFeatures2\test_Grouping.py
Here both sanity and regression tests will execute.
6. Parallel Testing
Pytest supports parallel testing using the “pytest-xdist” plugin. This plug-in allows you to parallelize test execution, which can significantly reduce the overall test suite runtime.
- Install ‘’pytest-xdist‘
Code:
It will execute different methods at the same time on different browsers by using parallel commands.
import pytest
import time
from selenium_firefox import Firefox
class TestParallel:
def test_LoginChrome(self):
from selenium.webdriver.common.by import By
selenium import webdriver
from selenium.webdriver.chrome.service import Service
self.serv_obj = Service("D:\\Drivers\\chromedriver-win64\\chromedriver.exe")
self.driver = webdriver.Chrome(service=self.serv_obj)
self.driver.get("https://opensource-demo.orangehrmlive.com/")
self.driver.maximize_window()
time.sleep(2)
self.driver.find_element(By.NAME, "username").send_keys("Admin")
self.driver.find_element(By.NAME, "password").send_keys("admin123")
self.driver.find_element(By.XPATH, "//button[@type='submit']").click()
self.act_title = self.driver.title
self.driver.exp_title = "OrangeHRM"
self.driver.quit()
def test_FirefoxLogin(self):
from selenium.webdriver.common.by import By
from selenium import webdriver
Starting with selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.firefox.service import Service as FirefoxService
# Initialize Firefox driver instance
self.driver = webdriver.Firefox(service=FirefoxService(executable_path=GeckoDriverManager().install()))
self.driver.maximize_window()
self.driver.get("https://opensource-demo.orangehrmlive.com/")
time.sleep(2)
self.driver.find_element(By.NAME, "username").send_keys("Admin")
self.driver.find_element(By.NAME, "password").send_keys("admin123")
self.driver.find_element(By.XPATH,"//button[@type='submit']").click()
self.act_title = self.driver.title
self.driver.exp_title = "OrangeHRM"
self.driver.quit()
Output:
- Command to execute: pytest -v -s -n=2 pytestFeatures2\test_Parallel.py
-n: specify the exact number of worker processes.
Conclusion
Combining selenium with pytest empowers you to create a robust and maintainable test suite for your web application. It provides a powerful and flexible solution for ensuring the quality and reliability of your web projects.