Introduction
Automation testing is an essential part of modern software development. As web applications become more complex, organisations need reliable automation frameworks to test functionality, improve test coverage and reduce repetitive manual testing.
Selenium WebDriver with Python is a popular combination for browser automation. However, writing individual Selenium scripts is not enough for large projects. Testers need a structured framework that supports reusable components, test data management, reporting, logging and maintainable test execution.
A well-designed Selenium Python automation framework helps teams organise test cases, reduce code duplication and integrate automated tests into continuous integration pipelines.
In this tutorial, we will build a practical Selenium Python automation framework from scratch using PyTest and the Page Object Model.
1. What Is an Automation Testing Framework?
An automation testing framework is a structured collection of guidelines, reusable components, libraries and utilities used to develop and execute automated test cases.
A Selenium Python framework may contain:
Selenium WebDriver for browser automation.
PyTest for test execution.
Page Object Model for organising page interactions.
Fixtures for browser setup and cleanup.
Excel or CSV files for test data.
Logging for execution details.
Reporting tools for test results.
Git for source code management.
Jenkins or GitHub Actions for CI/CD integration.
The objective is to create an organised and reusable testing solution rather than a collection of disconnected scripts.
2. Types of Selenium Automation Frameworks
Several framework approaches are commonly used in automation testing.
| Framework Type | Description |
|---|---|
| Linear framework | Simple scripts written sequentially |
| Modular framework | Application functionality divided into modules |
| Data-driven framework | Test data maintained separately from test logic |
| Keyword-driven framework | Actions represented through predefined keywords |
| Hybrid framework | Combines multiple framework approaches |
| BDD framework | Uses business-readable scenarios and steps |
A hybrid framework combining Page Object Model, PyTest fixtures and data-driven testing is a practical approach for many Python automation projects.
3. Technologies Required
We will use the following technologies:
Python 3.
Selenium WebDriver.
PyTest.
OpenPyXL for Excel-based test data, where needed.
PyTest HTML for reporting.
Python logging.
Git and GitHub for version control.
Install the core dependencies:
python -m pip install selenium pytest pytest-html openpyxlCreate a virtual environment:
python -m venv venvActivate it on Windows:
venv\Scripts\activateSelenium Manager can automatically manage compatible browser drivers in many current setups.
4. Designing the Framework Architecture
Before writing code, plan the framework structure.
A recommended project structure is:
selenium_python_framework/
│
├── pages/
│ ├── __init__.py
│ ├── base_page.py
│ ├── login_page.py
│ └── home_page.py
│
├── tests/
│ ├── __init__.py
│ ├── test_login.py
│ └── test_homepage.py
│
├── utilities/
│ ├── __init__.py
│ ├── config_reader.py
│ └── logger.py
│
├── testdata/
│ └── login_data.csv
│
├── reports/
│
├── logs/
│
├── conftest.py
├── pytest.ini
├── requirements.txt
└── README.mdUnderstanding the structure:
pages/: Contains page classes and web element interactions.tests/: Contains test scenarios and assertions.utilities/: Contains reusable helper functions.testdata/: Stores non-sensitive test data.reports/: Stores generated test reports.logs/: Stores execution logs.conftest.py: Manages shared PyTest fixtures.pytest.ini: Configures PyTest execution.
5. Creating the Base Page Class
The Base Page class contains reusable Selenium operations.
Create pages/base_page.py:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BasePage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def click(self, locator):
element = self.wait.until(
EC.element_to_be_clickable(locator)
)
element.click()
def enter_text(self, locator, text):
element = self.wait.until(
EC.visibility_of_element_located(locator)
)
element.clear()
element.send_keys(text)
def get_text(self, locator):
element = self.wait.until(
EC.visibility_of_element_located(locator)
)
return element.text
def is_visible(self, locator):
return self.wait.until(
EC.visibility_of_element_located(locator)
).is_displayed()
def get_title(self):
return self.driver.titleThis class can be inherited by other page objects, reducing repeated browser interaction code.
6. Creating the Login Page Object
Create pages/login_page.py:
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class LoginPage(BasePage):
USERNAME = (By.ID, "username")
PASSWORD = (By.ID, "password")
LOGIN_BUTTON = (By.ID, "login")
ERROR_MESSAGE = (By.ID, "error")
def enter_username(self, username):
self.enter_text(self.USERNAME, username)
def enter_password(self, password):
self.enter_text(self.PASSWORD, password)
def click_login(self):
self.click(self.LOGIN_BUTTON)
def login(self, username, password):
self.enter_username(username)
self.enter_password(password)
self.click_login()
def get_error_message(self):
return self.get_text(self.ERROR_MESSAGE)The login page class contains all the locators and methods associated with the login page.
The element IDs are illustrative and must be replaced with the actual application's locators.
7. Creating the Home Page Object
Create pages/home_page.py:
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class HomePage(BasePage):
HEADING = (By.TAG_NAME, "h1")
def get_heading(self):
return self.get_text(self.HEADING)
def is_displayed(self):
return self.is_visible(self.HEADING)This class provides reusable methods to verify the home page.
8. Creating Browser Fixtures in conftest.py
Fixtures manage browser creation and cleanup.
Create conftest.py:
import pytest
from selenium import webdriver
@pytest.fixture
def driver():
browser = webdriver.Chrome()
browser.maximize_window()
yield browser
browser.quit()Each test using this fixture receives a fresh browser session. The quit() operation runs during fixture teardown, including when a test fails.
9. Managing Application Configuration
Application URLs and environment settings should not be hardcoded throughout test scripts.
Create utilities/config_reader.py:
import configparser
from pathlib import Path
CONFIG_PATH = (
Path(__file__).resolve().parents[1]
/ "config.ini"
)
config = configparser.ConfigParser()
config.read(CONFIG_PATH)
BASE_URL = config["application"]["base_url"]Create config.ini in the project root:
[application]
base_url = https://example.comFor a real project, use separate configuration for development, testing and staging environments. Keep secrets outside version control, preferably in environment variables or an approved secrets manager.
10. Creating the First Automation Test
Create tests/test_login.py:
from pages.login_page import LoginPage
from pages.home_page import HomePage
from utilities.config_reader import BASE_URL
def test_valid_login(driver):
driver.get(BASE_URL + "/login")
login_page = LoginPage(driver)
login_page.login(
"testuser",
"testpassword"
)
home_page = HomePage(driver)
assert home_page.is_displayed()This test demonstrates how the test layer uses page objects to perform a login workflow and verify the resulting page.
The URL, credentials and page locators are placeholders. Use a dedicated test application and valid test accounts when implementing the example.
11. Adding Data-Driven Testing
A framework should support multiple test scenarios without duplicating test code.
PyTest parameterization provides a simple solution:
import pytest
@pytest.mark.parametrize(
"username,password,expected",
[
("validuser", "valid123", "success"),
("invaliduser", "wrong123", "error"),
("validuser", "wrong123", "error")
]
)
def test_login_scenarios(
driver,
username,
password,
expected
):
# Navigate to the application,
# perform login and verify expected result.
assert expected in ["success", "error"]For a production implementation, connect each scenario to the login page object and verify the actual application result against the expected outcome.
For larger test datasets, Excel, CSV or JSON files can be used.
12. Implementing Logging
Logging helps testers understand what happened during test execution.
Create utilities/logger.py:
import logging
from pathlib import Path
LOG_DIR = Path("logs")
LOG_DIR.mkdir(exist_ok=True)
logging.basicConfig(
filename=LOG_DIR / "automation.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)Use logging inside test scripts:
from utilities.logger import logger
def test_application():
logger.info("Starting application test")
assert True
logger.info("Application test completed")For a larger framework, configure logging handlers and log levels centrally, and avoid recording passwords or other sensitive information.
13. Generating Automation Test Reports
Install the reporting plugin:
python -m pip install pytest-htmlExecute the test suite:
pytest --html=reports/report.html --self-contained-htmlAn HTML report can display:
Total tests executed.
Passed test cases.
Failed test cases.
Skipped test cases.
Execution duration.
Error details.
Reports are useful for reviewing automation results and communicating test status to project stakeholders.
14. Running Tests Using PyTest Configuration
Create pytest.ini:
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
addopts = -vNow execute the framework using:
pytestRun only a particular test:
pytest tests/test_login.pyRun tests marked as smoke tests:
pytest -m smokeCustom markers should first be registered in the configuration file to avoid warnings.
15. Integrating Selenium Python with Git and Jenkins
A professional automation framework should be version-controlled and capable of running in a CI/CD pipeline.
Git and GitHub
Git helps manage changes to test scripts, page objects and configuration. GitHub provides a platform for collaboration and code review.
Common commands:
git init
git add .
git commit -m "Initial automation framework"Jenkins integration
A Jenkins pipeline can:
Retrieve the automation project from Git.
Set up Python.
Install dependencies.
Execute PyTest.
Generate HTML reports.
Publish test results.
Example shell execution:
python -m pip install -r requirements.txt
pytest --html=reports/report.html --self-contained-htmlFor CI environments, configure the browser and operating system dependencies appropriately. Headless execution can be used where a graphical browser display is unavailable.
16. Best Practices for Framework Development
Follow a consistent project structure.
Apply Page Object Model appropriately.
Use reusable fixtures and utilities.
Separate test data from test scripts.
Use explicit waits for dynamic elements.
Keep test cases independent.
Maintain clear logging and reporting.
Store configuration separately from application logic.
Avoid committing passwords and secrets.
Use Git for version control.
Integrate automation into CI/CD.
Review and maintain flaky tests regularly.
A framework should remain simple enough for the team to understand while providing the features required by the project.
17. Career Opportunities in Selenium Python Framework Development
Framework development is an important step in progressing from basic automation scripting to advanced automation engineering.
Relevant career roles include:
Automation Test Engineer.
Python Automation Tester.
Selenium Framework Developer.
QA Automation Engineer.
Software Development Engineer in Test (SDET).
Test Automation Lead.
Candidates should be able to explain framework architecture, fixtures, Page Object Model, data-driven testing, reporting and CI/CD integration.
Learn Selenium Python Automation Testing with Palium Skills
Palium Skills offers practical Automation Testing training for freshers, graduates, manual testers and working professionals.
The Selenium Python learning pathway can include:
Python programming fundamentals.
Selenium WebDriver.
Locators and web element handling.
PyTest framework.
Page Object Model.
Data-driven automation testing.
Framework development from scratch.
Logging and reporting.
Git, Jenkins and CI/CD fundamentals.
Real-time automation projects.
Interview preparation.
Training modes include classroom sessions at South Kolkata and Salt Lake, Kolkata, and instructor-led live online sessions for learners across India.
Contact Palium Skills
Website: www.paliumskills.com
Call: 8420594969 / 7044871915
WhatsApp: 9903130500
Email: info@paliumskills.com
South Kolkata Centre: 1st Floor, Sheeba Bhavan, 1/22 Poddar Nagar, Near South City Mall, Kolkata – 700068.
Salt Lake Centre: 5th Floor, RDB Boulevard, Block GP, Salt Lake Electronic Complex, Kolkata – 700091.
Frequently Asked Questions
1. What is a Selenium Python automation framework?
It is a structured testing solution built using Selenium and Python, with reusable components for browser automation, test execution, reporting and data management.
2. Which testing framework is commonly used with Selenium Python?
PyTest is a popular choice because of its fixtures, parameterization, assertions and plugin ecosystem.
3. What is the Page Object Model?
POM is a design pattern in which application pages are represented by classes containing their locators and reusable interaction methods.
4. Can Selenium Python frameworks support data-driven testing?
Yes. They can use Excel, CSV, JSON, databases and PyTest parameterization to execute multiple test scenarios.
5. Can Selenium Python be integrated with Jenkins?
Yes. Jenkins can execute PyTest scripts as part of a CI/CD pipeline and publish the generated test reports.
6. Is Python suitable for large automation frameworks?
Yes. Python can support large automation projects when the framework is properly designed, modularised and maintained.
7. What should I learn after building a Selenium Python framework?
You can progress to API automation, Playwright, Docker, CI/CD, advanced reporting, cloud browser execution and test architecture.