🐍 Создайте автотест Web UI на Python и Selenium за 7 шагов: инструкция для новичков
Если вам нужно тестировать веб-интерфейсы и логику отображения графических блоков на странице или просто автоматизировать работу в браузере, эта статья для вас. Читайте инструкцию по созданию автотеста на Python и Selenium за 7 простых шагов.
Мы будем использовать Selenium совместно с Python версий 3.x.x. Цель статьи – не дать фундаментальные знания по теории программирования и написания автотестов, а заинтересовать в этой области и показать, как они пишутся в целом.
1. Установка необходимых компонентов
Для начала работы нам потребуется установить Python на рабочую машину.
Переходим на официальный сайт Python и качаем установщик для вашей ОС (мы будем использовать Windows). В процессе инсталляции поставьте галочки на добавлении компонентов в системные переменные PATH. Дождитесь завершения процесса, и если программа попросит перезагрузки, перезагрузитесь. Если у вас Linux, интерпретатор может уже присутствовать в системе, в противном случае стоит установить его из репозитория пакетов вашего дистрибутива.
Проверьте корректность установки, перейдите в терминал (в Windows нажмите Win+R и запустите cmd или Alt+Ctrl+T в графической среде Linux). Выполните следующую команду:
Далее нам понадобится сам Selenium:
Дождитесь завершения установки. Поскольку мы будем писать тест, воспользуемся популярной библиотекой pytest. Устанавливается она аналогично:
Для создания приложений нужна интегрированная среда разработки или IDE (integrated development environment), но можно писать код и в обычном текстовом редакторе. Я выбрал самую популярную и удобную среду PyCharm от компании JetBrains.
Чтобы работать с браузером, помимо Selenium потребуется веб-драйвер: в нашем случае ChromeDriver – по сути это связующее звено в цепочке. Обратите внимание, что версия драйвера должна соответствовать версии браузера и вперед – к созданию проекта и написанию первого скрипта.
2. Первый скрипт с использованием драйвера
Все компоненты готовы, давайте создадим новый проект. Для
этого запускаем PyCharm и в открывшимся окне выбираем New Project.
Указываем
имя проекта и нажимаем Create.
Напишем первый тест, чтобы проверить работоспособность драйвера.
В качестве примера ресурса для тестирования возьмем
популярный сайт для практики автоматизированного тестирования: https://www.saucedemo.com.
Кейс:
Зайти на страницу.
Найти элемент по id.
Вывести в консоль сообщение с результатом поиска.
После
ввода кода необходимо установить библиотеку Selenium в наш проект.
Для
этого нажмите на подсвеченный текст в редакторе, нажмите Alt + Enter и далее
выберите Install package selenium. Это нужно делать для
каждого неустановленного пакета.
Запустить сценарий можно во встроенном эмуляторе терминала IDE или в любом другом:
Если все установлено правильно, должен запуститься браузер,
который откроет страницу. Результатом запуска нашего сценария на Python, будет
сообщение: “Элемент найден”.
3. Поиск элементов
В нашем скрипте присутствует следующая строка:
Метод find_element_by_id позволяет процессу найти элемент в разметке HTML по наименованию атрибута id. В реализации драйвера есть несколько способов поиска элементов на странице: по name, xpath, css, id. Поиск по css и xpath являются более универсальным, но он сложнее для начинающих. Использование поиска по name и id намного удобнее, но в практической разработке используется редко. Далее я буду использовать только xpath.
Теперь
давайте напишем кейс аутентификации пользователя на странице входа:
Шаг 1: пользователь вводит корректный username и password.
Шаг 2: нажимает кнопку ввода.
Ожидаемый результат: пользователь попадает на главную страницу магазина. Проверка заголовка на соответствие “PRODUCTS”.
Разберем
пример пошагово:
Для работы с формой найдем и присвоим элементы переменным input_username, input_password и login_button с помощью xpath.
Далее вызовем для элемента метод send_keys с данными, которые хотим передать в текстовое поле. В нашем случае в username отправляем "standart_user", в password – "secret_sauce". Проецируя поведение пользователя нажимаем Enter для ввода данных, используя метод send_keys для найденной кнопки с переданным аргументом Keys.RETURN. Этот аргумент позволяет работать с действиями клавиатуры в Selenium, аналогично нажатию на Enter на клавиатуре.
На главном экране нам необходимо найти и присвоить переменной элемент текста Products. Как я говорил раннее, не всегда есть возможность найти элемент по id – здесь как раз тот случай.
Путь xpath до элемента: //*[@id=\"header_container\"]/div[2]/span.
Чтобы найти путь xpath, зайдите на https://www.saucedemo.com и нажмите F12, чтобы открыть инструменты разработчика. Затем выберите стрелку-указатель и кликните по элементу до которого хотите найти путь. В нашем случае до Products.
Откроется код элемента в дереве HTML, далее нужно открыть контекстное меню выделенной строки и скопировать xpath.
Если кратко рассматривать путь, то //* обозначает, что будут найдены все элементы на странице, а [@id=\"header_container\"] обозначает условие поиска (будут найдены все элементы на странице с тэгом id = "header_container").И далее /div[2]/span – спускаемся на второй дочерний элемент div и далее на дочерний элемент span. Сравните полученный xpath с деревом элемента в инструментах разработчика – сразу станет понятно что к чему.
Тут мы просто сравниваем текст найденного элемента с ожидаемым значением и выводим в консоль сообщение.
При выполнении скрипта получили следующий результат:
4. Первый тест с поиском и переходом по странице
Кейс:
Введем логин и пароль пользователя и зайдем на главную страницу.
Найдем позицию с названием "Sauce Labs Fleece Jacket".
Перейдем на страницу товара и нажмем кнопку добавления в корзину.
Перейдем в корзину и проверим что там присутствует 1 позиция с названием "Sauce Labs Fleece Jacket".
Из
нового тут добавился только метод click(), который просто кликает по
найденному элементу.
После прохождения всех шагов в консоль выводится результат, что в
корзине имеется товар.
Ожидания в selenium: что нужно знать?
В предыдущем кейсе с большой вероятностью можно столкнуться с проблемой, когда при нажатии на позицию мы сразу кликаем на корзину. При медленном интернете или долгом ответе от сервера в корзину может ничего не добавиться. Для таких случаев предусмотрены ожидания.
Selenium driver поддерживает два вида ожиданий: явное (explicit) и неявное (implicity). Для явных ожиданий есть специальные методы, которые помогут рационально использовать время выполнения теста: например, можно установить минимальное время ожидания и возвращать элемент, если он прогрузился раньше предполагаемого времени.
Примерявногоожидания:
Процесс ждет 10 секунд пока элемент станет доступным, чтобы по
нему можно было кликнуть. Если элемент так и не прогрузился и недоступен для
клика, генерируется исключение TimeoutException.
Неявные ожидания в свою очередь устанавливаются один раз для
драйвера, а не для каждого элемента. Включается неявное ожидание, когда Selenium не может найти элемент: он ждет установленное время и если не дождется, тоже возвращает TimeoutException. В отличии от явного ожидания, этот тип менее гибок и может оказать плохое влияние на общее время прогона
тестов.
Пример неявного ожидания:
Ожидать действия можно и с помощью time.sleep(5). У нас в
примерах есть использование этого метода, но оно считается плохой практикой и обычно применяется только для дебага.
5. Рефакторинг теста, добавление ожиданий
Чтобы
pytest понял, что перед ним именно тестовая, а не обычная функция, сама тестовая функция
должна начинаться с test_.
Обновим наш тест, добавим необходимые ожидания для
стабильности тестовых функций.
Также я вынес отдельную функцию под ожидания, куда мы просто
передаем xpath и driver в виде аргументов.
Для запуска теста с помощью pytest в терминале введите
pytest main.py. После прохождения всех этапов должен отобразиться результат
прохождения.
6. Проверки, проверки, проверки
Мы плавно перешли к заключительному этапу написания теста – проверке вывода по известному ответу. Хотя тест выполняется успешно, он ничего
не проверяет и является бессмысленным. Будем использовать
стандартные инструкции assert или утверждения. Суть инструмента – проверить, что результат соответствует наши ожиданиям. Если соответствует, наш тест будет
считаться пройденным, а в противном случае – проваленным.
Добавим в тест проверки. Будем проверять, что название
куртки "Sauce Labs Fleece Jacket" и описание как в магазине.
Теперь при расхождении результата и ожидаемого
условия будет возвращена ошибка прохождения. Укажем название куртки "Sauce Labs Fleece Jacket1". Результат выполнения скрипта будет следующим:
7. Распределим логику
Теперь причешем код, распределив логику по
методам, как, например, было с wait_of_element_located. Разбивать логику необходимо
для написания множества тестов.
В этом примере логика поделилась на функциональные компоненты (фикстуры). Теперь аутентификация пользователя будет происходить в отдельной функции, что позволит не производить одни и те же действия и дублировать код при каждом тесте, в котором нужно проходить аутентификацию. В качестве примера использования фикстур сделана инициализация драйвера, что позволит использовать инстанс драйвера во всех тестах, не пересоздавая его. Логика добавления товара в корзину тоже была вынесена в отдельный функциональный компонент для дальнейшего использования.
Суть разнесения логики заключается в принципе конструктора: собирать тесты из отдельных частей, подставляя только необходимые данные при переиспользовании функций в разных тестах.
При желании можно и дальше проводить рефакторинг кода.
Рекомендации по архитектуре
Очевидно, что в одном файле хранить все вспомогательные функции и тесты неудобно. После добавления еще нескольких тестов даже с распределенной логикой скрипт будет похож на полотно с трудночитаемым кодом. К тому же если вы разрабатываете тесты с коллегами, без конфликтов в коде не обойтись. Для начала нужно разделить проект на модули: в одном будут находиться файлы с тестами, в другом частичная логика, в третьем – ресурсы, в четвертом – утилиты и т.д.
Далее следует переходить на разработку автотестов с использованием объектно-ориентированного программирования. Это сэкономит массу времени и поможет в написании сложного и лаконичного кода.
Стоит также обратить внимание на паттерны проектирования, особенно на PageObject и PageFactoroy. В эффективном тестировании UI они играют большую роль.
Все тестовые данные лучше хранить в неизменяемых классах, константах или в отдельных файлах (json, csv).
Заключение
На этом создание первого автотеста закончено. Некоторые
моменты были рассмотрены поверхностно, что дает возможность пытливым умам
поглотить информацию из других источников. Удачи!
Комментарии