Selenium remains one of the most widely adopted frameworks for web automation, with millions of developers and QA engineers using it to test applications across browsers. Pairing Selenium with Python creates a powerful and flexible automation environment.
According to the Stack Overflow Developer Survey, Python is among the top three most popular programming languages globally, primarily due to its readability, versatility, and extensive ecosystem. This combination makes Selenium Python one of the go-to choices for modern test automation.
Python is a preferred language for Selenium automation for several reasons:
Download Python from the official website and ensure you check the option “Add Python to PATH”.
Verify installation:
python --version
pip --version
Selenium can be installed directly from PyPI:
pip install selenium
WebDriver is the core component of Selenium that interacts directly with browsers. It mimics user actions like clicking, typing, navigating, and validating elements. Unlike Selenium RC, WebDriver communicates natively with browsers, making it faster and more reliable.
Selenium provides Python bindings that expose WebDriver APIs to Python developers. These bindings allow direct browser manipulation through Python code, such as:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
print(driver.title)
driver.quit()
A simple example of launching a browser and performing a search:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://www.google.com")
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("Selenium Python")
search_box.send_keys(Keys.RETURN)
print(driver.title)
driver.quit()
Here are some of the sample code and instructions to locate web elements in Selenium Python:
Locating elements is a core part of Selenium automation. Common strategies include:
find_element(By.ID, "elementId")
find_element(By.NAME, "username")
find_element(By.CLASS_NAME, "btn-primary")
find_element(By.XPATH, "//input[@type='text']")
find_element(By.CSS_SELECTOR, "div.container > input")
Once elements are located, the next step in automation is to interact with them in ways that simulate real user behavior. Selenium Python provides a wide range of methods to perform actions such as clicking buttons, entering text into fields, selecting checkboxes, working with forms, and handling dropdown menus.
These interactions form the core of functional testing, as they validate whether the application responds correctly to user input.
driver.find_element(By.LINK_TEXT, "About").click()
driver.find_element(By.ID, "username").send_keys("test_user")
Submit forms directly by pressing ENTER:
form = driver.find_element(By.ID, "loginForm")
form.submit()
checkbox = driver.find_element(By.ID, "subscribe")
if not checkbox.is_selected():
checkbox.click()
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.ID, "country"))
select.select_by_visible_text("India")
Selenium Python allows traversal of nested page structures, enabling interactions with navigation links, headers, and form elements within the DOM.
Move between different sections by interacting with <a> tags.
Headers can be validated to confirm proper page structure.
Use XPath with parent-child relations:
driver.find_element(By.XPATH, "//form[@id='signup']//input[@name='email']")
driver.switch_to.frame("iframeName")
driver.switch_to.default_content()
driver.switch_to.window(driver.window_handles[1])
from selenium.webdriver import ActionChains
action = ActionChains(driver)
element = driver.find_element(By.ID, "draggable")
target = driver.find_element(By.ID, "droppable")
action.drag_and_drop(element, target).perform()
from selenium.webdriver.common.keys import Keys
driver.find_element(By.NAME, "q").send_keys(Keys.CONTROL, 'a')
driver.implicitly_wait(10)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamicElement"))
)
Allows polling with custom intervals and ignored exceptions.
alert = driver.switch_to.alert
print(alert.text)
alert.accept() #
or
alert.dismiss()
Assertions are an integral part of automated testing because they verify whether the actual outcome of a test matches the expected result. In Selenium Python, assertions are used to validate page content, element properties, or application behavior. Proper use of assertions ensures that test failures highlight real defects rather than false positives.
There are two primary ways to use assertions in Selenium tests:
1. Hard Assertions
Commonly used methods in unittest:
self.assertEqual(actual, expected) # Check equality
self.assertTrue(condition) # Check if condition is True
self.assertIn("Dashboard", driver.title) # Check substring presence
Example with unittest:
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestAssertions(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://example.com")
def test_title(self):
self.assertIn("Example Domain", self.driver.title)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
2. Soft Assertions (Verifications)
Example using pytest-check:
import pytest_check as check
def test_multiple_validations(driver):
driver.get("https://example.com")
check.is_in("Example", driver.title)
check.is_true(driver.find_element(By.TAG_NAME, "h1").is_displayed())
import csv
with open('testdata.csv') as file:
reader = csv.reader(file)
for row in reader:
print(row)
Integrate data providers with pytest.mark.parametrize for running tests with multiple inputs.
driver.save_screenshot("error.png")
While Selenium provides the foundation for web automation, integrating it with testing frameworks enhances test structure, execution, and reporting. Two of the most popular Python frameworks for Selenium are unittest and pytest.
unittest is Python’s built-in testing framework and is often the first choice for developers starting with automation. It supports structured test cases with setup and teardown methods for initializing and closing browser sessions. For example:
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
class GoogleSearchTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.google.com")
def test_search(self):
search_box = self.driver.find_element(By.NAME, "q")
search_box.send_keys("Selenium Python")
search_box.submit()
self.assertIn("Selenium Python", self.driver.title)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
The setup and teardown methods ensure the environment is consistent across test runs, while assertions validate expected outcomes.
pytest is widely adopted for Selenium automation due to its rich feature set and simplicity. It supports fixtures for test setup and teardown, parameterization for data-driven testing, and plugins for reporting. A sample implementation:
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
@pytest.fixture
def driver():
driver = webdriver.Chrome()
yield driver
driver.quit()
def test_google_search(driver):
driver.get("https://www.google.com")
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("Selenium Python")
search_box.submit()
assert "Selenium Python" in driver.title
pytest enables parallel test execution with plugins like pytest-xdist and generates detailed reports, making it ideal for large automation projects.
The Page Object Model (POM) is a design pattern that improves maintainability and readability of test scripts by separating page locators and interactions from the test logic. Instead of writing locators and actions repeatedly, they are stored in dedicated page classes.
Example structure:
from selenium.webdriver.common.by import By
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_input = (By.ID, "username")
self.password_input = (By.ID, "password")
self.login_button = (By.ID, "loginBtn")
def login(self, username, password):
self.driver.find_element(*self.username_input).send_keys(username)
self.driver.find_element(*self.password_input).send_keys(password)
self.driver.find_element(*self.login_button).click()
from selenium import webdriver
from login_page import LoginPage
def test_valid_login():
driver = webdriver.Chrome()
driver.get("https://example.com/login")
login_page = LoginPage(driver)
login_page.login("test_user", "password123")
assert "Dashboard" in driver.title
driver.quit()
By following POM, test code becomes easier to update and scale when application UIs change.
Beginners often face reliability issues because of common pitfalls in Selenium test design:
To build reliable and maintainable test suites with Selenium Python, follow these practices:
Selenium with Python is versatile but should be applied in the right scenarios:
Local setups often lack coverage for all browsers, versions, and devices. BrowserStack Automate solves this challenge by offering:
Selenium with Python is a powerful combination for automating modern web applications. From basic interactions with elements to advanced browser handling, it enables reliable and scalable test coverage.
With proper practices—like using POM, explicit waits, and test frameworks—teams can build resilient automation pipelines.
Leveraging BrowserStack’s real device cloud further enhances accuracy, speed, and efficiency, making Selenium Python a cornerstone of quality assurance in agile software development.
Run Selenium Tests on Cloud
Get visual proof, steps to reproduce and technical logs with one click
Continue reading
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop