[Тестирование IT-систем, Python, Тестирование веб-сервисов] Тестирование скриншотами
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Для будущих студентов курса «Python QA Engineer» подготовили авторскую статью.
Также приглашаем на открытый вебинар по теме «Непрерывная интеграция с Jenkins».Рассмотрим, как настраивать автоматический запуск тестов, устанавливать плагины и создавать бекапы конфигураций сборок.
Здравствуйте! Сегодня хочу рассказать о нашем опыте тестирования скриншотами с использованием python, selenium, и Pillow.Зачем? У нас был довольно большой (~1000) набор тестов на стеке python, pytest, selenium, которые отлично проверяли, что кнопки кликаются, а статистика отправляется (с использованием browserup proxy), но пропускали баги типа таких:
Используя только селениум, практически невозможно обнаружить такую неполадку, пока она не случится (не будешь же для каждого элемента добавлять проверку для каждого из его стилей). Также проблема в том, что у selenium’a трудности с определением видимости некоторых компонентов, а значит, и протестировать верстку с его помощью затруднительно. Посмотрим, как selenium определяет видимость для элементов карусели:
Скрипт:
from selenium.webdriver import Chrome
from collections import Counter
driver = Chrome()
driver.get("https://go.mail.ru/search?q=%D1%86%D0%B2%D0%B5%D1%82%D0%BE%D1%87%D0%BA%D0%B8%20%D0%BA%D0%B0%D1%80%D1%82%D0%B8%D0%BD%D0%BA%D0%B8")
elements = driver.find_elements_by_css_selector(".SmackPicturesContent-smackImageItem")
print(Counter([el.is_displayed() for el in elements]))
driver.quit()
Напечатает Counter({True: 10}), хотя видимых элементов явно не 10, и независимо от того, какой сегмент карусели отображается, количество «видимых» карточек не меняется, из-за чего невозможно проверить скролл. Аналогично будут работать и явные ожидания (visibility_of, visibility_of_all_elements_located, etc), так как они просто дергают у элемента is_displayed. РешениеНам был нужен инструмент для pytest и selenium, чтобы мы могли переиспользовать инфраструктуру, на которой крутились текущие тесты. После поиска выяснилось, что ничего готового нет, а то что есть — давно не поддерживается. Поэтому решили сделать сами. В общем это работает так:
- открываем страницу селениумом, готовим ее к тесту (заполняем поля, жмем кнопки);
- скриншотим всю страницу, и вырезаем кусок, на котором размещен компонент, который нужно протестировать;
- вырезаем его, повторяем все на стейджинге и попиксельно сравниваем получившиеся картинки;
- сами картинки перед сравнением нарезаем на блоки размером 40х40 пикселей, те участки которые не совпали помечаем красным прямоугольником для наглядности.
Таким образом можно протестировать и развалившуюся верстку, и компоненты страницы, для которых селениум не может корректно определить видимость.Рабочий пример на гитхабе.В итоге тест выглядит так:
def test_search_block(self):
self.driver.get("https://go.mail.ru/")
def action():
self.driver.find_element_by_xpath("//span[contains(text(), 'Соцсети')]").click()
self.check_by_screenshot((By.CSS_SELECTOR, ".MainPage-verticalLinksWrapper"), action=action)
В action кладем все нужные сетапы, при необходимости финализацию можно добавить аналогичным способом.После завершения теста у нас получится три изображения с тестинга, с прода и дифф. Все три добавляем в отчет.Благодаря плагину для аллюра отчет выглядит так:
И в случае падения:
Проблемы
- Антиалайзинг — особенно сильно флакали тесты, где на скриншот попадали svg. Решили «смазав» границу между цветами:
RED = "red"
GREEN = "green"
BLUE = "blue"
ALPHA = "alpha"
# https://github.com/rsmbl/Resemble.js/blob/dec5ae1cf1d10c9027a94400a81c17d025a9d3b6/resemble.js#L121
# https://github.com/rsmbl/Resemble.js/blob/dec5ae1cf1d10c9027a94400a81c17d025a9d3b6/resemble.js#L981
tolerance = {
RED: 32,
GREEN: 32,
BLUE: 32,
ALPHA: 32,
}
def _is_color_similar(self, a, b, color):
"""Проверить схожесть цветов. Для того, чтобы тесты не тригеррились на антиалиасинг допуски
в self.tolerance.
"""
if a is None and b is None:
return True
diff = abs(a - b)
if diff == 0:
return True
elif diff < self.tolerance[color]:
return True
return False
Так же сделано в Resemble.js. Надо сказать, что это диалектически влияет на надежность тестов. С одной стороны мы можем упустить проблемы с «одинаковыми» цветами, с другой тесты практически перестают моргать из-за сглаживания.Для особо тяжелых случаев просто удаляем проблемный элемент со страницы, например, так:
def test_search_block(self):
self.driver.get("https://go.mail.ru/")
def action():
element = self.driver.find_element_by_xpath("//span[contains(text(), 'Соцсети')]")
self.driver.execute_script("arguments[0].remove()", element)
self.check_by_screenshot((By.CSS_SELECTOR, ".MainVerticalsNav-listItemActive"), action=action)
Примерно так же можно добавить элементу заливку, удалить изображение, и т.д.
- На скриншотах появлялись затухающие скроллбары. Невозможно сделать скриншоты так, чтобы момент анимации у скроллов совпал — из-за этого тесты сильно флакали. В итоге помогло включение хэдлесс режима — скроллбары пропали.
- Не актуальные эталоны — проблема решилась сама собой благодаря отказу от эталонов. Заодно нет проблемы с необходимостью следить за тем, чтобы эталоны были сделаны там же, где гоняются тесты (на разных платформах разные шрифты и не только).
- Для мобильных тестов (андроид эмуляторы и эмуляция в хроме) нужно учитывать плотность пикселей. Так получаем размеры и координаты элемента:
def _get_raw_coords_by_locator(self, locator_type, query_string):
"""Без учета плотности пикселей."""
wait = WebDriverWait(self.driver, timeout=10, ignored_exceptions=Exception)
wait.until(lambda _: self.driver.find_element(locator_type, query_string).is_displayed(),
message="Невозможно получить размеры элемента, элемент не отображается")
el = self.driver.find_element(locator_type, query_string)
location = el.location
size = el.size
x = location["x"]
y = location["y"]
width = location["x"] + size['width']
height = location["y"] + size['height']
return x, y, width, height
А так делаем поправку на плотность пикселей:
def _get_coords_by_locator(self, locator_type, query_string) -> Tuple[int, int, int, int]:
x, y, width, height = self._get_raw_coords_by_locator(locator_type, query_string)
return x * self.pixel_ratio, y * self.pixel_ratio, width * self.pixel_ratio, height * self.pixel_ratio
Если не учесть этого, скриншотится будет все что угодно, кроме нужных элементов.Размер элементов, которые возвращает селениум:
from selenium.webdriver import Chrome, ChromeOptions
options = ChromeOptions()
options.add_experimental_option("mobileEmulation", {'deviceName': "Nexus 5"})
options.add_argument('--headless')
caps = options.to_capabilities()
driver = Chrome(desired_capabilities=caps)
driver.get("https://go.mail.ru/")
print(driver.find_element_by_xpath("//body").size)
driver.save_screenshot("test.png")
driver.quit()
Напечатает: {'height': 640, 'width': 360} для боди страницы.И в тоже время вернет скриншот размером 1080 х 1920:
❯ file test.png
test.png: PNG image data, 1080 x 1920, 8-bit/color RGBA, non-interlaced
4.Тесты никогда не будут зелеными во время релиза. Любые изменения в покрытых компонентах заставят тесты покраснеть, или сделают их сравнение невозможным (если расползутся размеры на тестинге и стейджинге). У этого есть и плюс: на диффе в отчете сразу видны изменения, в том числе те, которых не ожидали. ИтогСейчас у нас ~570 скриншот-тестов в двух сборках (мобильная и десктопная). Каждая сборка запущена в 20 потоков, и идет около 15 минут. С учетом изменений в релизах, которых ломают тесты, флакающих — не больше 2-3%. В основном тесты падают из-за регресса, или изменений в верстке. Писать их тоже достаточно легко, при необходимости проверку скриншотами можно совместить с обычными для селениум-тестов проверками (текст, кликабельность, видимость). Полезные ссылки про тестирование скриншотами:
- https://blog.rinatussenov.com/automating-manual-visual-regression-tests-with-python-and-selenium-be66be950196
- https://www.youtube.com/watch?v=crbwyGlcXm0
Узнать подробнее о курсе «Python QA Engineer».Смотреть открытый вебинар по теме «Непрерывная интеграция с Jenkins».
===========
Источник:
habr.com
===========
Похожие новости:
- [Open source, Разработка игр, ООП, Развитие стартапа] Idewavecore. Ретроспектива
- [Python, Гаджеты, Искусственный интеллект, DIY или Сделай сам] Как за 60$ создать систему распознавания лиц с помощью Python и Nvidia Jetson Nano 2GB (перевод)
- [JavaScript, Программирование] Зависимости JavaScript: Все, что вы когда-либо хотели знать, но боялись спросить (перевод)
- [Серверное администрирование, Тестирование веб-сервисов] Почему веб-производительность внутренних систем важна и нуждается в оптимизации? (перевод)
- [Python, Программирование, Big Data, Визуализация данных, Звук] Популярность BPM в разных жанрах музыки. Анализ скорости исполнения 500 лучших песен
- [JavaScript, Программирование] Почему вы можете обойтись без Babel (перевод)
- [Разработка веб-сайтов, Python, Django] Новое тестирование фичей в Django 3.2 (перевод)
- [SQL] Секционирование таблиц и время компиляции плана запроса в SQL Server (перевод)
- [Open source, OpenStreetMap, Открытые данные, Визуализация данных] День открытых данных 2021. Онлайн
- [Python, Машинное обучение, Искусственный интеллект, TensorFlow] Нейродайджест: главное из области машинного обучения за февраль 2021
Теги для поиска: #_testirovanie_itsistem (Тестирование IT-систем), #_python, #_testirovanie_vebservisov (Тестирование веб-сервисов), #_python, #_python_qa, #_jenkins, #_selenium, #_pillow, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_testirovanie_itsistem (
Тестирование IT-систем
), #_python, #_testirovanie_vebservisov (
Тестирование веб-сервисов
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:29
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Для будущих студентов курса «Python QA Engineer» подготовили авторскую статью.
Также приглашаем на открытый вебинар по теме «Непрерывная интеграция с Jenkins».Рассмотрим, как настраивать автоматический запуск тестов, устанавливать плагины и создавать бекапы конфигураций сборок. Здравствуйте! Сегодня хочу рассказать о нашем опыте тестирования скриншотами с использованием python, selenium, и Pillow.Зачем? У нас был довольно большой (~1000) набор тестов на стеке python, pytest, selenium, которые отлично проверяли, что кнопки кликаются, а статистика отправляется (с использованием browserup proxy), но пропускали баги типа таких: Используя только селениум, практически невозможно обнаружить такую неполадку, пока она не случится (не будешь же для каждого элемента добавлять проверку для каждого из его стилей). Также проблема в том, что у selenium’a трудности с определением видимости некоторых компонентов, а значит, и протестировать верстку с его помощью затруднительно. Посмотрим, как selenium определяет видимость для элементов карусели: Скрипт: from selenium.webdriver import Chrome
from collections import Counter driver = Chrome() driver.get("https://go.mail.ru/search?q=%D1%86%D0%B2%D0%B5%D1%82%D0%BE%D1%87%D0%BA%D0%B8%20%D0%BA%D0%B0%D1%80%D1%82%D0%B8%D0%BD%D0%BA%D0%B8") elements = driver.find_elements_by_css_selector(".SmackPicturesContent-smackImageItem") print(Counter([el.is_displayed() for el in elements])) driver.quit()
def test_search_block(self):
self.driver.get("https://go.mail.ru/") def action(): self.driver.find_element_by_xpath("//span[contains(text(), 'Соцсети')]").click() self.check_by_screenshot((By.CSS_SELECTOR, ".MainPage-verticalLinksWrapper"), action=action) И в случае падения: Проблемы
RED = "red"
GREEN = "green" BLUE = "blue" ALPHA = "alpha" # https://github.com/rsmbl/Resemble.js/blob/dec5ae1cf1d10c9027a94400a81c17d025a9d3b6/resemble.js#L121 # https://github.com/rsmbl/Resemble.js/blob/dec5ae1cf1d10c9027a94400a81c17d025a9d3b6/resemble.js#L981 tolerance = { RED: 32, GREEN: 32, BLUE: 32, ALPHA: 32, } def _is_color_similar(self, a, b, color):
"""Проверить схожесть цветов. Для того, чтобы тесты не тригеррились на антиалиасинг допуски в self.tolerance. """ if a is None and b is None: return True diff = abs(a - b) if diff == 0: return True elif diff < self.tolerance[color]: return True return False def test_search_block(self):
self.driver.get("https://go.mail.ru/") def action(): element = self.driver.find_element_by_xpath("//span[contains(text(), 'Соцсети')]") self.driver.execute_script("arguments[0].remove()", element) self.check_by_screenshot((By.CSS_SELECTOR, ".MainVerticalsNav-listItemActive"), action=action)
def _get_raw_coords_by_locator(self, locator_type, query_string):
"""Без учета плотности пикселей.""" wait = WebDriverWait(self.driver, timeout=10, ignored_exceptions=Exception) wait.until(lambda _: self.driver.find_element(locator_type, query_string).is_displayed(), message="Невозможно получить размеры элемента, элемент не отображается") el = self.driver.find_element(locator_type, query_string) location = el.location size = el.size x = location["x"] y = location["y"] width = location["x"] + size['width'] height = location["y"] + size['height'] return x, y, width, height def _get_coords_by_locator(self, locator_type, query_string) -> Tuple[int, int, int, int]:
x, y, width, height = self._get_raw_coords_by_locator(locator_type, query_string) return x * self.pixel_ratio, y * self.pixel_ratio, width * self.pixel_ratio, height * self.pixel_ratio from selenium.webdriver import Chrome, ChromeOptions
options = ChromeOptions() options.add_experimental_option("mobileEmulation", {'deviceName': "Nexus 5"}) options.add_argument('--headless') caps = options.to_capabilities() driver = Chrome(desired_capabilities=caps) driver.get("https://go.mail.ru/") print(driver.find_element_by_xpath("//body").size) driver.save_screenshot("test.png") driver.quit() ❯ file test.png
test.png: PNG image data, 1080 x 1920, 8-bit/color RGBA, non-interlaced
Узнать подробнее о курсе «Python QA Engineer».Смотреть открытый вебинар по теме «Непрерывная интеграция с Jenkins».
=========== Источник: habr.com =========== Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_testirovanie_itsistem ( Тестирование IT-систем ), #_python, #_testirovanie_vebservisov ( Тестирование веб-сервисов ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:29
Часовой пояс: UTC + 5