Selenium и Python: создание стабильных автотестов от А до Я

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Новички в области автоматизации тестирования, желающие освоить Selenium и Python.
  • Специалисты и практикующие QA-инженеры, интересующиеся улучшением своих навыков и инструментов.
  • Студенты, обучающиеся на курсах или самостоятельно изучающие тестирование программного обеспечения.

    Автоматизированное тестирование — мощный инструмент для тех, кто ценит время и качество. Selenium с Python стал золотым стандартом в этой области благодаря простоте синтаксиса и широким возможностям. Перед вами подробное руководство для всех, кто хочет научиться писать надежные тесты, избегая хрупких решений и бесконечных правок. Освоив эти техники, вы сможете автоматизировать однообразные проверки и сосредоточиться на действительно сложных задачах тестирования. 🚀

Хотите стать профессиональным тестировщиком и получать достойную оплату за свои навыки? Курс тестировщика ПО от Skypro разработан под реальные требования работодателей. За 9 месяцев вы освоите не только Selenium с Python, но и полный стек инструментов QA-инженера. Программа включает работу с реальными проектами, менторство от практикующих специалистов и гарантию трудоустройства. Инвестируйте в навыки, которые точно окупятся!

Настройка Selenium в Python для автоматизации тестов

Прежде чем писать первую строчку кода для автоматизации, необходимо правильно настроить рабочее окружение. Этот этап часто вызывает затруднения у новичков, но следуя четкому алгоритму, вы избежите большинства проблем.

Начнем с установки необходимых компонентов:

  1. Установите Python (рекомендуется версия 3.8 и выше)
  2. Установите Selenium WebDriver через pip: pip install selenium
  3. Загрузите драйвер для вашего браузера (ChromeDriver, GeckoDriver для Firefox и т.д.)
  4. Добавьте путь к драйверу в системные переменные PATH

Для тех, кто предпочитает автоматизированный подход, существует удобный способ установки веб-драйверов с помощью WebDriver Manager:

pip install webdriver-manager

Это избавит вас от необходимости вручную загружать и обновлять драйверы. В коде это выглядит так:

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())

Проверьте корректность установки, написав простой скрипт:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.python.org')
print(driver.title)
driver.quit()

Если код выполнился без ошибок и вы увидели заголовок страницы Python.org в консоли — поздравляю, базовая настройка завершена! 🎉

Браузер Драйвер Установка через webdriver-manager
Chrome ChromeDriver webdriver_manager.chrome.ChromeDriverManager().install()
Firefox GeckoDriver webdriver_manager.firefox.GeckoDriverManager().install()
Edge EdgeDriver webdriver_manager.microsoft.EdgeChromiumDriverManager().install()
Safari Встроен в macOS Не требуется (только включить Developer Tools)

Настоятельно рекомендую создать виртуальное окружение для ваших тестов, чтобы избежать конфликтов с другими проектами:

python -m venv selenium_env
source selenium_env/bin/activate # для Linux/Mac
selenium_env\Scripts\activate # для Windows

Михаил Прокофьев, Lead QA Engineer

Когда я только начинал работать с Selenium, я потратил почти два дня на попытки заставить его корректно работать. Главная проблема была в несоответствии версий браузера и драйвера. После очередного обновления Chrome тесты просто перестали запускаться. Тогда я узнал про webdriver-manager, и это изменило всё. Теперь я использую его во всех проектах и рекомендую команде. Один раз настроив CI/CD с автоматическим обновлением драйверов, мы забыли о проблемах совместимости. Мой совет: не экономьте время на правильной настройке окружения — это сэкономит вам недели работы в будущем.

Пошаговый план для смены профессии

Первые шаги: поиск и взаимодействие с элементами

После успешной настройки окружения пора научиться находить элементы на веб-странице и взаимодействовать с ними. Это фундаментальные навыки для любого автоматизатора тестирования. 🔍

Selenium предлагает несколько способов поиска элементов:

  • findelementby_id — поиск по атрибуту id (наиболее эффективный)
  • findelementby_name — поиск по атрибуту name
  • findelementby_xpath — поиск с помощью XPath выражений
  • findelementbycssselector — поиск с помощью CSS-селекторов
  • findelementbyclassname — поиск по имени класса
  • findelementbytagname — поиск по имени тега
  • findelementbylinktext — поиск ссылки по точному тексту
  • findelementbypartiallink_text — поиск ссылки по части текста

Однако современный подход предполагает использование метода find_element с указанием локатора:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get('https://www.python.org')

# Поиск элемента по ID
search_box = driver.find_element(By.ID, 'id-search-field')

# Поиск элемента по CSS-селектору
submit_button = driver.find_element(By.CSS_SELECTOR, 'button.search-button')

После нахождения элемента вы можете выполнять с ним различные действия:

# Ввод текста в поле
search_box.send_keys('selenium python')

# Клик по кнопке
submit_button.click()

# Очистка текстового поля
search_box.clear()

# Проверка отображения элемента
is_displayed = search_box.is_displayed()

# Получение атрибута элемента
placeholder = search_box.get_attribute('placeholder')

Иногда нужно найти несколько элементов сразу. Для этого используйте метод find_elements:

# Найти все ссылки на странице
all_links = driver.find_elements(By.TAG_NAME, 'a')

# Перебор найденных элементов
for link in all_links:
print(link.get_attribute('href'))

При работе с элементами часто требуется подождать их появления на странице. Selenium предлагает три типа ожиданий:

  1. Неявные ожидания (Implicit Waits) — глобальная настройка для всех элементов
  2. Явные ожидания (Explicit Waits) — ожидание конкретного условия для элемента
  3. Fluent ожидания (FluentWait) — гибкие ожидания с дополнительными параметрами
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Неявное ожидание
driver.implicitly_wait(10) # секунд

# Явное ожидание
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'results'))
)

Локатор Скорость Стабильность Когда использовать
ID Высокая Высокая Первый выбор, если доступен
CSS Высокая Средняя Когда нужна гибкость и нет ID
XPath Низкая Средняя В сложных случаях или при динамической структуре
Имя класса Средняя Низкая Только если класс уникален и стабилен
Текст ссылки Средняя Низкая Для ссылок при отсутствии других стабильных атрибутов

Навигация и управление браузером через Selenium

Управление браузером — это больше, чем просто поиск и взаимодействие с элементами. Selenium позволяет полностью контролировать поведение браузера: перемещаться по страницам, управлять окнами, работать с cookie и многое другое. 🌐

Основные действия по навигации:

# Открытие страницы
driver.get('https://www.python.org')

# Получение текущего URL
current_url = driver.current_url

# Получение заголовка страницы
title = driver.title

# Получение исходного кода страницы
page_source = driver.page_source

# Переход назад/вперед в истории браузера
driver.back()
driver.forward()

# Обновление страницы
driver.refresh()

При работе с многооконными приложениями или вкладками важно уметь переключаться между ними:

# Открытие новой вкладки
driver.execute_script("window.open('https://www.selenium.dev', '_blank')")

# Получение списка идентификаторов окон
window_handles = driver.window_handles

# Переключение на новую вкладку (обычно последнюю в списке)
driver.switch_to.window(window_handles[-1])

# Переключение обратно на первую вкладку
driver.switch_to.window(window_handles[0])

# Закрытие текущей вкладки
driver.close()

# Закрытие всех вкладок и завершение сеанса
driver.quit()

Для работы с всплывающими окнами (alerts) используйте следующие методы:

# Переключение на алерт
alert = driver.switch_to.alert

# Получение текста алерта
alert_text = alert.text

# Принятие алерта (нажатие OK)
alert.accept()

# Отклонение алерта (нажатие Cancel)
alert.dismiss()

# Ввод текста в алерт (если поддерживается)
alert.send_keys('Текст для ввода')

Часто требуется управлять cookies, особенно при тестировании авторизации:

# Добавление cookie
driver.add_cookie({"name": "session_id", "value": "12345"})

# Получение всех cookies
all_cookies = driver.get_cookies()

# Получение конкретной cookie
session_cookie = driver.get_cookie("session_id")

# Удаление cookie
driver.delete_cookie("session_id")

# Удаление всех cookies
driver.delete_all_cookies()

Для выполнения JavaScript на странице используйте метод execute_script:

# Выполнение простого скрипта
driver.execute_script("return document.title")

# Прокрутка до элемента
element = driver.find_element(By.ID, "my-element")
driver.execute_script("arguments[0].scrollIntoView(true);", element)

# Скрытие элемента
driver.execute_script("arguments[0].style.display='none';", element)

Для настройки размеров и позиции окна браузера:

# Установка размеров окна
driver.set_window_size(1920, 1080)

# Установка позиции окна
driver.set_window_position(0, 0)

# Разворачивание окна на весь экран
driver.maximize_window()

# Сворачивание окна
driver.minimize_window()

Анна Сергеева, Senior Test Automation Engineer

В одном из моих проектов мы столкнулись с проблемой: после авторизации пользователя в приложении нам нужно было протестировать функциональность, доступную только в новой вкладке. При каждом запуске теста система генерировала новую вкладку, но наши скрипты продолжали работать в исходной. Тесты стабильно падали. Мы перепробовали разные способы, пока не нашли решение: после действия, открывающего новую вкладку, мы стали получать список всех открытых окон через windowhandles и явно переключаться на нужную вкладку. Эта простая строчка кода спасла нам недели работы и превратила нестабильные тесты в надежные: `driver.switchto.window(driver.window_handles[-1])`. Теперь это стандартная практика в нашей тестовой базе, и новички в команде быстро учатся применять этот паттерн.

Создание комплексных тестов с Selenium и Python

Отдельные команды Selenium полезны для изучения, но в реальной работе вы будете создавать комплексные тесты, объединяющие множество действий. Давайте рассмотрим, как структурировать тесты, используя современные подходы и фреймворки. 🧩

Для организованного тестирования рекомендую использовать unittest или pytest. Рассмотрим пример с pytest, который более гибок и современен:

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.fixture
def browser():
driver = webdriver.Chrome()
driver.implicitly_wait(10)
yield driver
driver.quit()

def test_python_search(browser):
# Открываем страницу
browser.get("https://www.python.org")

# Находим поле поиска и вводим запрос
search_field = browser.find_element(By.ID, "id-search-field")
search_field.clear()
search_field.send_keys("pycon")

# Нажимаем кнопку поиска
browser.find_element(By.ID, "submit").click()

# Проверяем, что результаты поиска отображаются
WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "list-recent-events"))
)

# Проверяем, что "pycon" присутствует в результатах
results = browser.find_elements(By.CSS_SELECTOR, ".list-recent-events li")
assert len(results) > 0, "Результаты поиска не найдены"

# Проверяем текст в результатах
page_text = browser.page_source.lower()
assert "pycon" in page_text, "Запрос 'pycon' не найден в результатах"

Для более структурированного подхода рекомендуется использовать паттерн Page Object Model (POM), который отделяет логику тестов от их реализации:

# file: pages.py
from selenium.webdriver.common.by import By
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

def find_element(self, locator, time=10):
return WebDriverWait(self.driver, time).until(
EC.presence_of_element_located(locator),
message=f"Can't find element by locator {locator}"
)

class MainPage(BasePage):
def __init__(self, driver):
super().__init__(driver)
self.url = "https://www.python.org"

def open(self):
self.driver.get(self.url)

def search_for(self, query):
search_field = self.find_element((By.ID, "id-search-field"))
search_field.clear()
search_field.send_keys(query)
submit_button = self.find_element((By.ID, "submit"))
submit_button.click()

class SearchResultsPage(BasePage):
def get_results(self):
results_list = self.find_element((By.CLASS_NAME, "list-recent-events"))
items = results_list.find_elements(By.TAG_NAME, "li")
return items

def has_results(self):
return len(self.get_results()) > 0

def contains_text(self, text):
page_text = self.driver.page_source.lower()
return text.lower() in page_text

# file: test_search.py
import pytest
from selenium import webdriver
from pages import MainPage, SearchResultsPage

@pytest.fixture
def browser():
driver = webdriver.Chrome()
yield driver
driver.quit()

def test_python_search_with_pom(browser):
# Инициализация страниц
main_page = MainPage(browser)
results_page = SearchResultsPage(browser)

# Выполнение теста
main_page.open()
main_page.search_for("pycon")

# Проверки
assert results_page.has_results(), "Результаты поиска не найдены"
assert results_page.contains_text("pycon"), "Запрос 'pycon' не найден в результатах"

Для создания надежных тестов важно учитывать следующие принципы:

  1. Изоляция тестов — каждый тест должен быть независимым от других
  2. Идемпотентность — возможность многократного запуска без изменения результата
  3. Атомарность — тест должен проверять одну конкретную функциональность
  4. Явные ожидания — всегда используйте их вместо time.sleep()
  5. Корректная очистка — всегда освобождайте ресурсы (driver.quit(), а не driver.close())

Для параметризации тестов и запуска с разными данными используйте возможности pytest:

import pytest

@pytest.mark.parametrize("query,expected_text", [
("pycon", "pycon"),
("django", "web framework"),
("flask", "micro framework")
])
def test_python_search_parametrized(browser, query, expected_text):
main_page = MainPage(browser)
results_page = SearchResultsPage(browser)

main_page.open()
main_page.search_for(query)

assert results_page.has_results(), f"Результаты для запроса '{query}' не найдены"
assert results_page.contains_text(expected_text), f"Текст '{expected_text}' не найден в результатах"

Полезные приемы и решение проблем в Selenium Python

Даже опытные автоматизаторы регулярно сталкиваются с трудностями при работе с Selenium. Рассмотрим типичные проблемы и проверенные способы их решения. 🔧

1. Создание скриншотов при падении теста

Это незаменимый инструмент диагностики проблем, особенно в CI/CD окружении:

def test_function(browser):
try:
# Тестовая логика
browser.get("https://www.example.com")
# ...
except Exception as e:
# Создание скриншота с временной меткой
import time
timestamp = int(time.time())
screenshot_path = f"error_{timestamp}.png"
browser.save_screenshot(screenshot_path)
print(f"Screenshot saved at {screenshot_path}")
raise # Передаем исключение дальше

2. Обход CAPTCHA в тестовом окружении

Для тестовых сред обычно можно договориться о специальном режиме:

  • Используйте тестовые учетные записи с отключенной CAPTCHA
  • Добавьте специальный флаг в URL или cookie для отключения CAPTCHA
  • Для Google reCAPTCHA можно использовать ключ для тестирования: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

3. Работа с динамическими элементами

Один из самых сложных аспектов автоматизации — это взаимодействие с динамическими элементами:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import StaleElementReferenceException

# Переопределяем функцию для повторных попыток при устаревшей ссылке на элемент
def click_with_retry(driver, locator, max_attempts=3):
for attempt in range(max_attempts):
try:
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(locator)
)
element.click()
return True
except StaleElementReferenceException:
if attempt == max_attempts – 1:
raise
print(f"StaleElementReferenceException, retrying... (attempt {attempt+1}/{max_attempts})")

# Использование
click_with_retry(driver, (By.ID, "dynamic-button"))

4. Работа с загрузкой файлов

Для автоматизации загрузки файлов используйте метод send_keys с абсолютным путем к файлу:

import os

# Получаем абсолютный путь к файлу
file_path = os.path.abspath("path/to/file.txt")

# Находим элемент загрузки и передаем путь
file_input = driver.find_element(By.ID, "fileUpload")
file_input.send_keys(file_path)

5. Обработка всплывающих окон и модальных диалогов

Существует два типа всплывающих элементов — JavaScript-алерты и HTML-модальные окна:

# Для JavaScript-алертов
try:
WebDriverWait(driver, 5).until(EC.alert_is_present())
alert = driver.switch_to.alert
alert.accept() # или alert.dismiss()
except:
print("No alert present")

# Для HTML-модальных окон
modal = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "modal-dialog"))
)
close_button = modal.find_element(By.CLASS_NAME, "close-btn")
close_button.click()

Проблема Симптом Решение
ElementNotInteractableException Элемент найден, но не доступен для клика Использовать WebDriverWait с EC.elementtobe_clickable или JavaScript-клик
StaleElementReferenceException Ссылка на элемент устарела после обновления DOM Повторно находить элемент перед каждым взаимодействием
TimeoutException Элемент не появился в течение заданного времени Увеличить таймаут, проверить локатор, проверить видимость элемента
NoSuchElementException Элемент не найден на странице Проверить локатор, добавить ожидания, проверить фрейм
WebDriverException Соединение с браузером потеряно Проверить версии драйвера и браузера, использовать webdriver-manager

6. Эффективное отладка тестов

Для диагностики проблемных тестов:

  • Используйте явный вывод информации: print(f"Current URL: {driver.current_url}")
  • Создавайте скриншоты в ключевых точках: driver.save_screenshot("step_3.png")
  • Логируйте HTML-код проблемных элементов: print(element.get_attribute('outerHTML'))
  • Используйте Python debugger (pdb) для пошагового выполнения

7. Управление окнами и фреймами

При работе с iframe необходимо переключаться между ними:

# Переключение на iframe по индексу
driver.switch_to.frame(0)

# Переключение на iframe по ID или имени
driver.switch_to.frame("iframe-id")

# Переключение на iframe по элементу
iframe = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe)

# Возврат к основному содержимому
driver.switch_to.default_content()

8. Эмуляция различных устройств и разрешений экрана

Для тестирования отзывчивого дизайна:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()

# Эмуляция мобильного устройства
mobile_emulation = {
"deviceName": "iPhone X"
}
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)

driver = webdriver.Chrome(options=chrome_options)

# Или просто установка определенного разрешения
driver.set_window_size(375, 812) # iPhone X размеры

Автоматизированное тестирование с Selenium и Python — это мощный инструмент в руках тестировщика, позволяющий освободить время от рутинных проверок. Изучив основы и освоив практические приемы из этой статьи, вы сможете создавать надежные и эффективные тесты для ваших проектов. Помните главное правило автоматизации: тест должен быть стабильнее, чем код, который он проверяет. Инвестируйте время в хорошую архитектуру, грамотное управление ожиданиями и обработку исключений — это окупится многократно при поддержке и расширении вашей тестовой базы.

Загрузка...