Selenium автотесты на Python

Полное руководство по Selenium автотестам: от установки до продвинутых техник написания стабильных автоматизированных тестов

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

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

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

Главное преимущество Selenium — кроссбраузерность. Пишешь тест один раз, запускаешь в Chrome, Firefox, Safari. Работает везде (ну, почти). Ещё один плюс — бесплатный и с открытым исходником. Не нужно платить за лицензии, можно крутить и на своём ноутбуке, и на сервере компании.

Selenium WebDriver — сердце системы

WebDriver — это программный интерфейс, который связывает ваш код с браузером. Вы пишете команды на Python (или другом языке), а WebDriver переводит их в действия браузера. Между вашим скриптом и браузером стоит драйвер — отдельная программа для каждого браузера.

ChromeDriver для Chrome. GeckoDriver для Firefox. EdgeDriver для Edge. Каждый из них понимает команды по стандарту W3C WebDriver и знает как заставить конкретный браузер выполнить нужное действие.

Архитектура простая: ваш Python-скрипт отправляет HTTP-запросы драйверу, драйвер управляет браузером, браузер возвращает результаты обратно. Всё это происходит быстро, хотя иногда бывают задержки… об этом позже поговорим.

Готовим окружение 🛠️

Первое — ставим Python. Если у вас уже стоит версия 3.8+, отлично. Если нет, качаем с официального сайта, устанавливаем, проверяем командой python --version.

Второе — устанавливаем сам Selenium. Открываем терминал и пишем:

pip install selenium

Готово. Библиотека установлена. Но это ещё не всё.

Третье — драйверы браузеров. Вот тут начинается веселье. Нужно скачать исполняемый файл драйвера под вашу операционку. ChromeDriver для Windows — это .exe файл, для Linux и Mac — просто исполняемый бинарник. Скачали? Отлично. Теперь нужно положить его туда, откуда система сможет его найти.

Самый простой способ — добавить путь к драйверу в переменную PATH. На Windows это делается через свойства системы. На Linux и Mac можно просто переместить драйвер в /usr/local/bin. Или указать путь явно в коде, но это менее удобно.

Про виртуальное окружение. Да, лучше создать. Команда python -m venv venv создаст отдельную папку для всех зависимостей проекта. Активируешь его, ставишь туда Selenium и другие библиотеки — и они не конфликтуют с другими проектами на твоём компьютере.

IDE и инструменты

PyCharm — хороший выбор. VS Code тоже норм, легче и быстрее. Ставишь расширения для Python, и всё работает из коробки. Автодополнение, подсветка синтаксиса, встроенный отладчик. Без этого писать код можно, но будет больно.


Первые шаги с WebDriver

Открываем любимый редактор, создаём файл test.py и пишем:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://google.com")
print(driver.title)
driver.quit()

Запускаем. Если всё настроено правильно, откроется окно Chrome, загрузится Google, в консоли выведется заголовок страницы, и браузер закроется. Вот и весь первый автотест 🎉

Метод get() открывает URL. title возвращает заголовок страницы. quit() закрывает браузер полностью, вместе со всеми вкладками. Есть ещё close(), но он закрывает только текущую вкладку.

Можно управлять размером окна. driver.maximize_window() развернёт его на весь экран. driver.set_window_size(1920, 1080) установит конкретные размеры. Полезно, если тестируешь адаптивную вёрстку.

Навигация: driver.back(), driver.forward(), driver.refresh(). Всё как в обычном браузере, только программно.

Ищем элементы на странице

Вот это уже интереснее. Чтобы кликнуть на кнопку или ввести текст в поле, нужно сначала найти этот элемент. Selenium предлагает несколько способов поиска:

  • По ID — самый надёжный, если у элемента есть уникальный id
  • По имени класса — class=»button-submit»
  • По CSS-селектору — как в стилях, очень гибко
  • По XPath — мощный, но может быть хрупким
  • По тексту ссылки — для тегов <a>
  • По имени тега — найти все <button> на странице

Пример:

from selenium.webdriver.common.by import By

element = driver.find_element(By.ID, "search-input")
element.send_keys("Selenium автотесты")
element.submit()

Тут мы нашли поле ввода по ID, ввели текст и отправили форму. Метод find_element возвращает первый найденный элемент. Если хочешь найти все совпадения, используй find_elements (с s на конце) — вернёт список.

XPath выглядит страшно, но иногда без него никуда. Например, нужно найти кнопку внутри конкретного div с определённым классом. CSS-селектор может не справиться, а XPath типа //div[@class='form-wrapper']//button решит проблему.

Что делать с найденными элементами

click() — кликнуть. send_keys("текст") — ввести текст. clear() — очистить поле ввода. Базовые операции, которые покрывают 80% сценариев.

Выпадающие списки требуют отдельного подхода. Для них есть класс Select:

from selenium.webdriver.support.ui import Select

dropdown = Select(driver.find_element(By.ID, "country"))
dropdown.select_by_visible_text("Россия")

Можно выбирать по значению, по индексу, по видимому тексту. Удобно.

Для сложных взаимодействий типа drag-and-drop или наведения мыши есть ActionChains. Создаёшь цепочку действий, а потом выполняешь их одной командой perform(). Выглядит примерно так:

from selenium.webdriver.common.action_chains import ActionChains

actions = ActionChains(driver)
actions.move_to_element(element).click().perform()

Окна, фреймы, алерты

Бывает, что на сайте открывается новое окно или вкладка. Selenium по умолчанию остаётся в старом окне, нужно явно переключиться:

driver.switch_to.window(driver.window_handles[1])

window_handles — это список всех открытых окон. Первое окно — индекс 0, второе — индекс 1.

С iframe тоже нужно переключаться. Если элемент внутри iframe, просто так его не найдёшь:

driver.switch_to.frame("frame-name")
# теперь можно работать с элементами внутри
driver.switch_to.default_content()  # вернуться обратно

JavaScript alert, confirm, prompt — всплывающие окна браузера. Их нельзя найти как обычные элементы, но можно обработать:

alert = driver.switch_to.alert
print(alert.text)
alert.accept()  # нажать OK
# или alert.dismiss() для Cancel

Ожидания — боль и спасение

Вот честно, большинство проблем с нестабильными тестами из-за ожиданий. Страница загружается не моментально. Элементы появляются с задержкой. AJAX-запросы возвращают данные когда им вздумается. И если твой тест пытается кликнуть на кнопку, которой ещё нет на странице — привет, NoSuchElementException.

Неявные ожидания

Самый простой способ — включить неявное ожидание один раз в начале теста:

driver.implicitly_wait(10)

Теперь при каждом поиске элемента Selenium будет ждать до 10 секунд, пока элемент не появится в DOM. Удобно, но не всегда работает как надо. Если элемент в DOM есть, но ещё невидим или неактивен, неявное ожидание не поможет.

Явные ожидания

Явные ожидания — это когда ты говоришь: жди конкретное условие для конкретного элемента. Намного гибче:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))

Тут мы ждём, пока кнопка не станет кликабельной. Не просто появится в DOM, а именно станет доступна для клика. Есть куча других условий: видимость элемента, наличие текста, изменение атрибута.

Явные ожидания спасают от flaky tests — тестов, которые то проходят, то падают без явной причины. Используйте их. Всегда.

⚠️ Главное правило: никогда не используй time.sleep(5). Это зло. Тест будет тормозить на пять секунд даже если элемент появился через полсекунды. Плюс это ненадёжно — иногда пяти секунд не хватит.


Pytest для организации 📦

Когда тестов становится больше трёх, нужна структура. Pytest — стандарт для Python-тестирования. Устанавливается просто:

pip install pytest

Создаёшь файлы с именами вида test_*.py или *_test.py. Внутри пишешь функции с префиксом test_. Запускаешь командой pytest — и все тесты прогоняются автоматически.

Фикстуры — вот где настоящая магия. Это функции, которые выполняются перед тестами (setup) и после (teardown). Для Selenium фикстура обычно создаёт WebDriver перед тестом и закрывает его после:

import pytest
from selenium import webdriver

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

Теперь в каждом тесте просто указываешь browser как параметр:

def test_google_search(browser):
    browser.get("https://google.com")
    assert "Google" in browser.title

Pytest автоматически вызовет фикстуру, передаст драйвер в тест, а после выполнения закроет браузер. Красиво и чисто.

Маркировка и параметризация

Можно помечать тесты маркерами. Например, какие-то тесты — smoke, какие-то — regression:

@pytest.mark.smoke
def test_login(browser):
    # тест авторизации

Потом запускаешь только smoke-тесты командой pytest -m smoke. Удобно для быстрых проверок перед релизом.

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

@pytest.mark.parametrize("query", ["Python", "Java", "JavaScript"])
def test_search(browser, query):
    # тест выполнится три раза с разными запросами

Меньше дублирования кода, больше покрытие.


Page Object Model — порядок в хаосе

Когда тестов десятки, а то и сотни, начинается ад с поддержкой. Изменился локатор кнопки на сайте — нужно править во всех тестах. Добавили новое поле в форму — опять везде лезть. Page Object Model (POM) решает эту проблему.

Идея простая: создаёшь отдельный класс для каждой страницы сайта. В классе описываешь все элементы и действия с этой страницей. Тесты не работают напрямую с WebDriver и локаторами — они вызывают методы page objects.

Например, класс для страницы поиска:

class SearchPage:
    def __init__(self, driver):
        self.driver = driver
        self.search_input = (By.NAME, "q")
        self.search_button = (By.NAME, "btnK")
    
    def search(self, query):
        element = self.driver.find_element(*self.search_input)
        element.send_keys(query)
        self.driver.find_element(*self.search_button).click()

Теперь в тесте просто:

def test_search(browser):
    page = SearchPage(browser)
    page.search("Selenium")
    # проверки

Локатор изменился? Правишь в одном месте — в классе страницы. Все тесты продолжают работать.

Обычно создают базовый класс BasePage с общими методами для всех страниц: ожидания, клики, поиск элементов. А конкретные страницы наследуются от него и добавляют специфичные методы.

💡 Структура проекта с POM:

  • pages/ — классы страниц (base_page.py, main_page.py, search_page.py)
  • tests/ — тестовые сценарии (test_search.py, test_login.py)
  • conftest.py — общие фикстуры для всех тестов

Продвинутые фишки 🚀

JavaScript-магия

Иногда Selenium не может кликнуть на элемент. Он перекрыт другим элементом, или находится вне зоны видимости. В таких случаях можно выполнить JavaScript напрямую:

driver.execute_script("arguments[0].click();", element)

Прокрутка страницы тоже через JavaScript проще:

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

Можно изменять DOM, читать переменные из JS, делать что угодно. Это мощный инструмент, но злоупотреблять не стоит — тесты должны имитировать поведение реального пользователя, а пользователи JavaScript не выполняют.

Скриншоты и отчёты

Когда тест падает, хочется увидеть что пошло не так. Скриншот помогает:

driver.save_screenshot("error.png")

Можно сделать скриншот автоматически при падении теста через фикстуру pytest. В conftest.py добавляешь хук:

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    if report.when == "call" and report.failed:
        driver = item.funcargs['browser']
        driver.save_screenshot(f"{item.name}.png")

HTML-отчёты генерятся плагином pytest-html:

pip install pytest-html
pytest --html=report.html

Получаешь красивый отчёт с результатами всех тестов, временем выполнения, логами.

Обход детекции автоматизации 🕵️

Многие сайты научились распознавать Selenium. Яндекс, например, может заблокировать или показать капчу. Проблема в том, что браузер, управляемый Selenium, имеет определённые маркеры: свойство navigator.webdriver равно true, отсутствуют некоторые плагины.

Есть способы обойти:

  • Использовать библиотеку undetected-chromedriver — патченная версия ChromeDriver
  • Настроить опции для эмуляции реального пользователя
  • Добавить случайные задержки между действиями
  • Эмулировать движение мыши и прокрутку

Пример с опциями:

options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

Это не панацея, но помогает в большинстве случаев.


❓ Частые вопросы про Selenium автотесты

Q Какой язык программирования лучше выбрать для Selenium?

Python — наиболее популярный выбор из-за простого синтаксиса и быстрого старта. Java используют в крупных enterprise-проектах, где уже есть Java-разработчики. JavaScript подходит для фронтенд-команд, работающих с Node.js. C# выбирают компании с .NET-стеком. Для обучения и большинства задач рекомендую Python — меньше кода, больше готовых библиотек, активное комьюнити.

Q Можно ли использовать Selenium для мобильных приложений?

Selenium предназначен только для веб-приложений в браузерах. Для мобильных нативных приложений существует Appium — он построен на архитектуре WebDriver, но работает с iOS и Android приложениями. Если тестируете мобильную версию сайта в браузере — Selenium справится, можно даже эмулировать мобильные устройства через Chrome DevTools Protocol.

Q Почему мои тесты работают нестабильно?

Основная причина — неправильные ожидания. Замените все time.sleep() на явные ожидания WebDriverWait. Вторая причина — хрупкие локаторы типа XPath с индексами элементов. Используйте уникальные ID или data-атрибуты. Третья — гонка условий при параллельном запуске тестов на общих данных. Четвертая — нестабильность тестовой среды или самого сайта. Проверьте логи, добавьте скриншоты при падении, анализируйте паттерны ошибок.

Q Как ускорить выполнение Selenium тестов?

Запускайте тесты параллельно через pytest-xdist (команда pytest -n 4 для 4 потоков). Используйте headless режим браузера — без GUI тесты работают быстрее. Настройте Selenium Grid для распределения тестов между несколькими машинами. Отключите загрузку изображений и CSS через опции браузера, если они не критичны для тестов. Оптимизируйте сами тесты — убирайте лишние ожидания, объединяйте проверки где возможно.

Q Нужно ли знать JavaScript для работы с Selenium?

Базовые знания JavaScript полезны, но не обязательны для начала. Selenium предоставляет методы для большинства операций без JS. Продвинутые сценарии иногда требуют execute_script — тогда понимание JS поможет. Достаточно знать основы: как получить элемент, изменить его свойства, выполнить клик. Учите по мере необходимости — когда стандартных методов Selenium недостаточно.

Q Как тестировать приложения с двухфакторной аутентификацией?

Несколько подходов. Первый — договориться с разработчиками о тестовом окружении, где 2FA отключена или есть универсальный код. Второй — использовать cookies или токены авторизации напрямую через driver.add_cookie(), минуя форму логина. Третий — интегрироваться с API для получения кодов 2FA программно. Четвертый — использовать библиотеки типа pyotp для генерации TOTP-кодов из secret key.

Q Selenium или Playwright — что выбрать в 2025-26 году?

Selenium остается стандартом индустрии с огромным комьюнити и поддержкой всех браузеров. Playwright — современная альтернатива от Microsoft, быстрее работает, лучше с асинхронными операциями, встроенные ожидания умнее. Для новых проектов с modern stack рекомендую Playwright. Для существующих систем, интеграции с legacy или если команда уже знает Selenium — оставайтесь на нём. Оба инструмента отлично решают задачи автоматизации.