Легкое веб-тестирование с Python, Pytest и Selenium WebDriver, часть 4: первый тест при помощи Selenium WebDriver, Python и Chrome |
22.07.2020 00:00 |
Автор: Энди Найт (Andy Knight) Теперь WebDriver готов к работе – давайте напишем наш первый web-тест! Это будет простой поиск DuckDuckGo. DuckDuckGo – это поисковик, который не отслеживает пользовательские данные. Пользователи могут вводить запросы и получать ссылки на соответствующие сайты, как и в любой другой поисковой системе. Прежде чем писать код автоматизации, всегда стоит записать тест-процедуру обычным языком. Такое создание процедуры заставляет нас в первую и главную очередь думать о тестируемом поведении. Вот наша тест-процедура:
Это простенький тест, однако он полностью покрывает типичное поисковое поведение. Код Добавьте тест-функции в tests/test_web.py:
Функция test_basic_duckduckgo_search внедряет нашу тест-процедуру согласно паттерну "Подготовка-Действие-Проверка". Заметьте, что тест-функция объявляет параметр browser, имеющий имя, аналогичное фикстуре для настройки и очистки ChromeDriver. Pytest автоматически вызовет фикстуру и внедрит отсылку к WebDriver при каждом запуске этого теста. Затем тест-функция использует переменную browser для осуществления ряда вызовов WebDriver. Давайте посмотрим, как они работают. Подготовка URL = 'https://www.duckduckgo.com' Тест объявляет URL для домашней страницы DuckDuckGo как переменную для читабельности и поддерживаемости. PHRASE = 'panda' Это поисковый запрос, который будет использоваться в тесте. Так как тест покрывает "базовый" поиск, запрос не особенно важен. Тесты, проверяющие более сложное поведение, должны использовать более сложные запросы. Тест снова объявляет ее в начале тест-функции для читабельности и поддерживаемости. browser.get(URL) Начальная точка для теста – это домашняя страница DuckDuckGo. Этот вызов открывает заданный URL в браузере. Имейте, однако, в виду – этот вызов не ждет загрузки страницы. Он просто инициирует взаимодействие загрузки. Действие search_input = browser.find_element_by_id('search_form_input_homepage') Первый шаг в автоматизации веб-взаимодействий – это поиск целевого элемента (или элементов). Элементы могут как появляться на странице, так и не появляться. Автоматизация должна использовать локатор для поиска элемента, если он существует, а затем сконструировать объект, представляющий этот элемент. Существует множество типов локаторов – ID, имена классов, CSS-селекторы, XPath… Локаторы найдут все совпадающие элементы на странице – их может быть больше одного. Попробуйте использовать наиболее простой локатор, уникально идентифицирующий целевой элемент. Для создания локаторов нужно увидеть HTML-структуру страницы. Chrome DevTools упрощает исследование разметки любых страниц. Просто кликните на странице правой кнопкой и выберите "Inspect". Вы увидите все элементы на вкладке "Elements". Для нашего теста нам нужно поле ввода поискового запроса на домашней странице DuckDuckGo. Этот элемент имеет атрибут id со значением “search_form_input_homepage”, как показано ниже: Мы можем получить этот элемент, используя метод WebDriver find_element_by_id. Переменная search_input присваивается объекту, представляющему строку ввода запроса на странице. Помните, что так как ожидания у копии WebDriver неявные, он будет ожидать появления элемента ввода поискового запроса вплоть до десяти секунд. search_input.send_keys(PHRASE + Keys.RETURN) Когда элемент у нас на руках, мы можем инициировать взаимодействия с ним. Метод send_keys отправляет последовательность нажатий клавиш элементу search input – как сделал бы реальный пользователь при помощи клавиатуры. Вызов выше посылает поисковый запрос. Ключ RETURN в конце запускает поиск. Проверка (1) link_divs = browser.find_elements_by_css_selector('#links > div') Страница результатов должна отображать элемент div с ID "links", у которого есть дочерний элемент div для каждой результирующей ссылки. CSS-селектор выше находит все div результирующих ссылок. Заметьте, что "элементов" тут несколько – этот вызов вернет список. assert len(link_divs) > 0 Тест должен убедиться, что результаты для поискового запроса действительно появились. Это утверждение проверяет, что на странице найдена хотя бы одна результирующая ссылка. Проверка (2) xpath = f"//div[@id='links']//*[contains(text(), '{PHRASE}')]" Мы проверили, что какие-то результаты появились, но надо еще и убедиться, что результаты соответствуют нашему поисковому запросу. Для выявления ссылок, содержащих в тексте наш запрос, можно использовать XPath. XPath сложнее имен и CSS-селекторов, но и мощность у них повыше. Наш XPath ищет любой div с ID "links", а затем – его потомков, содержащих поисковый запрос. ("f" в начале строки для вас в новинку? Это f-строка, она упрощает форматирование!) phrase_results = browser.find_elements_by_xpath(xpath) Этот вызов находит все элементы, используя предварительно связанный XPath. Мы могли совместить эти две строки в одну, но разделение строк делает код более читабельным, и более "пайтоновским". assert len(phrase_results) > 0 Как и предыдущее утверждение, это убеждается, что найден как минимум один элемент. Это простая проверка работоспособности. Ее можно сделать более надежной – например, убедиться, что все результаты на странице содержат поисковый запрос – но это будет сложным делом. Не каждый результат может содержать поисковый запрос в точности. К примеру, некоторые могут отличаться регистром. Локаторы и логика продвинутой верификации должны быть куда сложнее. Так как это базовый тест поиска, достаточно более простой проверки. Проверка (3) search_input = browser.find_element_by_id('search_form_input') Финальная проверка убеждается, что поисковая строка все еще отображается в строке ввода. Строчка выше идентична вызову поиска элемента из стадии подготовки – она снова находит элемент строки поиска. Почему бы не воспользоваться объектом search_input снова? К сожалению, предыдущий элемент протух. Страница изменилась с домашней страницы на страницу результатов. Несмотря на то, что элементы выглядят одинаково, они не идентичны, и нам нужен новый локатор. Поэтому нам нужно получать свежий элемент. assert search_input.get_attribute('value') == PHRASE Текст, введенный в элемент поля ввода, доступен как его атрибут “value”. Эта строчка убеждается, что атрибут “value” равен поисковому запросу. Она проверяет, что запрос не испарился. Проверка и запуск веб-теста Полный код for tests/test_web.py теперь должен выглядеть так (с комментариями для ясности):
Давайте запустим тест, чтобы убедиться, что он работает:
При запуске веб-теста откроется Google Chrome. Вы увидите, как он автоматически введет поисковый запрос, дождется страницы результатов, а затем закроет браузер. Легко и просто! Если тест не запустился, проверьте:
Как насчет улучшений? Поздравляю с созданием вашего первого Web UI-теста! Это, безусловно, занимает больше времени, нежели юнит-тесты. Несмотря на то, что тест успешно запускается, мы можем сделать кое-что еще, дабы улучшить код. В следующий раз мы проведем рефакторинг этого теста, используя паттерн Page Object. |