Как заставить тесты «видеть» ошибки: элегантный способ автоматизации тестирования

Меня зовут Алексей Лакович, я занимаюсь автоматизацией тестирования в компании Генезис. В тестировании я работаю уже более 6 лет и накопил очень большой опыт как в автоматизации тестирования, так и в организации команд по ручному тестированию.

Я также организовал в Генезисе для наших тестировщиков и ребят из других компаний продвинутые курсы по автоматизации тестирования — для участия в них уже нужно иметь определенный опыт в тестировании. Я могу описать про это чуть подробнее в личку, моя почта находится в профиле — обращайтесь, если вы хотите профессионально развиваться в тестировании.

Хочу вам рассказать про одно из элегантных решений на тему визуального тестирования сайта/приложений. Я совсем недавно рассказывал про него на наших Беседах (мы раз в неделю или приглашаем в компанию внешнего спикера, или кто-то из компании делает выступление на какую-то из тем). Мне показалось, что про такое решение будет интересно узнать тем читателям DOU, которые занимаются автоматизацией тестирования.

Немного воды. Ручное тестирование я невзлюбил еще на первой неделе своей работы. Так как лень меня начала побеждать, и на этапе задачи «мы там выкатили пару фиксов/новый функционал/поменяли текст/{любое другое}, посмотри, пожалуйста, все ли ок?», я задумался — а ведь можно нехилый кусок такой рутинной работы автоматизировать. Кроме этого, после выкатки обновлений периодически какая-нибудь ссылка, либо картинка в футере на странице «Контакты» едет, и это может остаться незамеченным многие дни, а то и недели.

Данным способом «визуального тестирования» можно обнаруживать ошибки верстки, текстов, различия PROD и STAGE версий, отличия разных версий браузеров, а также все недочеты, которые можно «увидеть» при тестировании ПО.

Собственно идея проста: сравнение скриншотов приложения (Actual vs Expected) и получение разницы между ними.

У себя мы используем язык Java, Selenium WebDriver и очень неплохое решение от ребят из Яндекса — библиотеку aShot (огромный им привет и благодарность за такие инструменты, как aShot и Allure).

Если вы разрабатываете ваши тесты на других языках — подход остается тем же, так как основной принцип не меняется, а варианты технического решения всегда найдутся:
— Написать аналогичный инструмент для сравнения картинок.
— Воспользоваться уже имеющимися решениями (погуглить либо посмотреть в сторону универсального инструмента для работы с изображениями, например, imagemagick).

Логика теста. Первое, о чем хотелось бы написать — это о незамысловатой «логике» работы самого теста:
1. Браузер переходит по страницам и делает скриншоты страниц/элементов.
2. Если отсутствует эталонный снимок, то сделанный скриншот сохраняется в папку с «expected» скриншотами.
3. Далее вызывается метод для сравнения картинок (только что сделанного и эталонного снимков) и выдает результат — различие между ними в пикселях;
4. Если это значение == 0, то тест проходит успешно. Если же нет, то собирается гифка из скриншота эталона, актуального снимка и снимка с помеченными отличиями.
5. Все это дело формируется в отчет со всей информацией о тесте и сделанными снимками, и в случае провала приходит уведомление на почту.

Помимо этих шагов, конечно, есть дополнительные условия, такие как заданные допустимые отличия (числовое значение пикселей), игнорирование динамических элементов, подмена значений каунтеров/текста на странице — любых вещей, которые «мешают» или не особо важны.

Но в самом базовом случае можно обойтись и без лишних заморочек.

Также при первом запуске теста вы должны быть уверены, что ваш сайт отображается «правильно», и те снимки, которые были сделаны в процессе, будут действительно эталонными.

Самое главное в этом, как и в любом другом тесте — сделать реализацию максимально удобной для использования и гибкой для внесения изменений, которые имеют место быть в процессе поддержки автотестов.

Для начала определимся с основными частями реализации, которая нам нужна для написания подобных тестов:
1. Установить, настроить систему для работы.
2. Продумать структуру папок для хранения наших скриншотов.
3. Подумать над формированием имени файлов (не стоит недооценивать этот момент).
4. Делать снимок приложения в процессе теста.
5. Собственно сравнивать скриншоты Actual и Expected:
— иметь набор правил для валидации результата сравнения (допустимые отличия, игнорирование некоторых элементов);
— выводить результат сравнения в удобном для просмотра виде, чтобы не пришлось глазами искать разницу между снимками.

Установка/настройка окружения

Для того чтобы у нас все было готово к работе, мы должны установить:
1. JDK;
2. IntelliJ IDEA (+ драйвер для Хрома);
3. Maven (конечно, можно без него; по дефолту в IDEA он должен быть);
4. Selenium WebDriver;
5. Драйверы для нужных нам браузеров (если крутить будем локально);
6. TestNG/JUnit (тут тоже опционально);
7. Yandex AShot.

Это упрощенная версия, все подробности по настройке каждого из пунктов можно найти в интернете.

Не хочется много писать про установку каждого пункта, но опишу кое-что из важного. Скачиваем JDK, устанавливаем «IntelliJ IDEA», запускаем и создаем новый «Maven Project». Затем переходим к подключению нужных нам библиотек и фреймворков, подключаем зависимости в мавен pom.xml файл:

Selenium WebDriver

<!-- Selenium java client -->
<dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-java</artifactId>
   <version>3.0.1</version>
</dependency>
<!-- Selenium Server -->
<dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-server</artifactId>
   <version>3.0.1</version>
</dependency>

TestNG

<!--TestNG -->
<dependency>
   <groupId>org.testng</groupId>
   <artifactId>testng</artifactId>
   <version>6.9.10</version>
</dependency>

AShot

<!-- Yandex AShot -->
<dependency>
   <groupId>ru.yandex.qatools.ashot</groupId>
   <artifactId>ashot</artifactId>
   <version>1.5.2</version>
</dependency>

Структура папок

Мы должны продумать структуру папок для хранения снимков. Самый простой вариант — взять какую-либо корневую директорию с названием типа «testScreenshots» и в ней создать 4 директории под скриншоты. Данный пункт лучше реализовать программно, чтобы не приходилось в случае запуска теста на другой тачке создавать их вручную:

{yourMainDir}/testScreenshots/expected/ — папка с эталонными скриншотами;
{yourMainDir}/testScreenshots/actual/ — папка со скриншотами, сделанными в процессе выполнения теста;
{yourMainDir}/testScreenshots/markedImages/ — папка с наложенными друг на друга снимками и помеченными различиями между ними;
{yourMainDir}/testScreenshots/gifs/ — папка для хранения gif изображений (для удобства просмотра отличий будем склеивать expected, actual и markedImages).

Также можно для каждых отдельных наборов тестов добавить еще одну папку в адрес, и будет что-то типа — {yourMainDir}/myAwsomeTestSuite/testScreenshots/

В коде по этому пункту проблем быть не должно — записываем пути в переменные (expected, actual, markedImages, gifs) и делаем метод setter, который их назначает в случае, если для конкретного теста мы хотим изменить директорию, и соответственно создает эти папки в случае их отсутствия в системе.

Пример setter’а:

public void setRootScreenshotsDir(String absolutePath){
   resourcesImagesDir= absolutePath;
   expectedDir = resourcesImagesDir+"/expected/";
   actualDir = resourcesImagesDir+"/actual/";
   diffDir = resourcesImagesDir+"/diff/";
   resultGifsDir = resourcesImagesDir+"/gifs/";
   createFolders();// Метод который проверяет наличие папок file.exists() , в случае их отсутствия - создает (file.mkdirs())
}

Названия тестовых скриншотов

Название файла скриншота — это его уникальный идентификатор, по которому мы будем искать нужный нам эталонный скриншот. Это довольно важный момент, так как тесты могут быть написаны под разные браузеры и размер окон. Мы должны это учесть в назначении имени наших сохраняемых скриншотов.

У нас это делается следующим образом — наименование скриншота состоит из:
1. имя домена (слитно) — hitwecom;
2. название страницы\элемента — profile;
3. локализация — EN;
4. браузер — Chrome;
5. размер окна браузера — 1366×768;
6. любой другой параметр, который вам может понадобиться для идентификации снимка, например, версия браузера.

Ну и собственно сам файл будет иметь название hitwecom_profile_EN_Chrome_1366x768.png, либо для другого браузера/размера окна — hitwecom_profile_EN_Firefox_1280x1024.png.

В самом тесте при вызове метода для сравнения скриншотов приходится указывать только название элемента. Все остальные данные берутся автоматически перед сохранением файла с помощью driver().getCurrentUrl(); driver().manage().window().getSize(); параметрами, которые передаем в тест, такие как браузер и локализация.

Также тут стоит учесть, чтобы название файлов не отличалось при прогоне ваших тестов на стейдж сервере и на проде. Будет довольно удобно иметь заготовленные скриншоты с прода и сравнивать с тем, что пытаются выдать как «новый релиз» на стейдже.

Снятие и сохранение скриншота

Скриншот можно получать любым удобным для вас способом, данный «вид» тестирования можно применять не только для веб-приложений. Единственное отличие, которое у вас будет, — это то, как вы получаете сам снимок и проставляете координаты для игнорируемых блоков. Остальные пункты могут совершенно не отличаться.

В библиотеке aShot имеется своя реализация для снятия скриншота страницы либо веб-элемента с помощью ВебДрайвера.

Также нужно учесть, что наведение мышью на ссылки/блоки может влиять на внешний вид приложения, поэтому простым способом перед началом наших тестов просто уводим курсор в левый верхний угол экрана:

Robot bot = new Robot();
bot.mouseMove(0, 0);

Для страницы это выглядит следующим образом :

Screenshot screenshot1 = new AShot().takeScreenshot(driver);
// получаем скриншот страницы

Так как, к примеру, Хром не делает скриншот по всей высоте страницы — мы можем добавить к снятию скриншота shootingStrategy с аргументом scrollTimeout (значение в миллисекундах). Это задержка между скроллом и снятием следующей части страницы.

Снимок страницы со скроллом:

Screenshot screenshot = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(100)).takeScreenshot(driver);

Если у вас «фиксированный хедер» (как у нас на скрине выше), и при скролле он всегда находится вверху страницы, то его можно закрепить перед снимком, изменив ему атрибут «style»:

Если нужно сделать скриншот элемента, а не всей страницы — мы можем передать в метод takeScreenshot конкретный элемент и сделать его снимок:

Скриншот веб-элемента:

WebElement header = driver.findElement(By.cssSelector(".header"));
Screenshot screenshot = new AShot().takeScreenshot(driver, header);

Важно: по умолчанию для определения координат элемента используется jQuery. Если у вас на проекте отсутствует поддержка jQuery, то нужно указать использование WebDriverCoordsProvider для их определения с помощью WebDriver API:

Screenshot screenshot = new AShot().coordsProvider(new WebDriverCoordsProvider()).takeScreenshot(driver, header);

Сохраняем полученный скриншот в файл:

File actualFile = new File(actualDir+name+".png");
ImageIO.write(screenshot.getImage(), "png", actualFile);

Если же вы делаете скриншот с помощью других утилит, то получить объект Screenshot с нужным вам файлом можно, передав в конструктор класса Screenshot BufferedImage:

File file = new File("C:/myDir/page1.png");
BufferedImage image = ImageIO.read(file);
Screenshot screenshot = new Screenshot(image);

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

Тут у нас реклама и фото юзера на странице, которые могут изменяться:

Первый способ — редактирование. Перед снятием скриншота мы можем с помощью JavascriptExecutor выполнить скрипт на странице, которым убрать/изменить различного рода счетчики, рекламу, фото пользователей, закрепить хедер — любые элементы, которые могут давать «шум» при сравнении наших скриншотов.

К примеру, для того чтобы убрать рекламу, нам достаточно иметь метод типа:

public void removeElements(By by){
   List<WebElement> elementsList = driver.findElements(by);
   for(WebElement element : elementsList ) {            ((JavascriptExecutor)driver)
.executeScript("arguments[0].remove();", element);
   }
}

И передать в него селектор, например, рекламных блоков.

Если нам нужно изменить значение счетчика сообщений, мы можем вызвать метод для этих целей:

public void setElementAttribute(By by, String attr, String value){
   List<WebElement> elementList = driver.findElements(by);
   for(WebElement element : elementList ) {
       ((JavascriptExecutor)driver)
.executeScript("arguments[0].setAttribute('" + attr + "', '" + value + "');", element);
   }
}

Удобно находить уникальный селектор сразу для всех блоков рекламы либо каунтеров и редактировать их пачкой, для этого используем findElements метод. Так можно значительно уменьшить количество кода.

Ну и соответственно, если нам нужно изменить текст, то и для этого тоже у нас есть метод:

public void setElementText(By by, String text){
   List<WebElement> elementList = driver().findElements(by);
   for(WebElement element : elementList ){
       ((JavascriptExecutor)driver)
.executeScript("arguments[0].innerHTML = \""+text+"\";", element);
       WebDriverWait wait = new WebDriverWait(driver(), 5);
     wait.until(ExpectedConditions.textToBePresentInElement(element, text));
   }
}

Второй способ — игнорирование. Мы можем в метод для снятия скриншота передать Set<By> ignoredElements. Создаем Set из элементов, которые мы не хотим учитывать при сравнении скриншотов, и вызываем метод для снятия скриншота, заведомо передав этот список в AShot.

Перед снятием снимка будут найдены координаты и размер наших элементов на странице, и в момент сравнения эти элементы (точнее, координаты и размер блоков) не будут учитываться в результате.

Вот пример снятия скриншота с игнором некоторых элементов:

Set<By> setIgnoredElements = setIgnoredElements(By.cssSelector(".banner"), By.cssSelector(".userPhoto"));
Screenshot screenshot = new AShot().ignoredElements(setIgnoredElements).shootingStrategy(ShootingStrategies.viewportPasting(100)).takeScreenshot(driver());

Перед сравнением скриншотов у нас будут актуальный (actualScreenshot) и ожидаемый (expectedScreenshot) снимки. Все игнорируемые зоны сохранены в нашем actualScreenshot, и при сравнении нам нужно будет эти зоны передать в наш expectedScreenshot.

Вот скриншот после проставления игнорирования рекламных баннеров и блока с фото юзера по центру:

Осталась проблема со счетчиком сообщений — он помечается как «ошибка». Его мы просто уберем. Вызываем наш метод для удаления элементов перед снятием скриншота и делаем снимок:

removeElements(By.cssSelector(".counter"));
Set<By> setIgnoredElements = setIgnoredElements(By.cssSelector(".banner"), By.cssSelector(".userPhoto"));
Screenshot screenshot = new AShot().ignoredElements(setIgnoredElements).shootingStrategy(ShootingStrategies.viewportPasting(100)).takeScreenshot(driver());

Теперь у нас есть чистая страница, готовая к прогону тестов без лишних «шумов»:

Сравнение скриншотов

Для начала получаем актуальный снимок, как из примеров выше:

Screenshot actualScreenshot = new AShot().takeScreenshot(driver); // сохраним его для отчета
ImageIO.write(actualScreenshot.getImage(), "png", new File(actualDir+name+".png"));

После снятия актуального скриншота мы проверяем, есть ли у нас эталонный снимок для этой страницы. Если его нет, то записываем актуальный как эталонный.

Еще было бы неплохо сделать возможность автоматически «перезаписать» все эталонные снимки. Это бывает нужно, когда, например, у нас кардинально изменили дизайн либо добавили новый блок. Для этого создаем какой-нибудь boolean параметр, типа newScreenshots, и если при запуске теста мы передадим true, то перезаписываем снятый скриншот в папку expected.

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

Screenshot expectedScreenshot = new Screenshot(ImageIO.read(new File(expectedDir+name+".png")));

Если мы установили игнорируемые зоны, то должны передать их в наш ожидаемый снимок:

expectedScreenshot.setIgnoredAreas(actualScreenshot.getIgnoredAreas());

Далее, с помощью класса ImageDiffer вызовем метод для сравнения этих скриншотов:

ImageDiff diff = new ImageDiffer().makeDiff(expectedScreenshot, actualScreenshot);

И, собственно, получим результат сравнения. Различие снимков в пикселях:

//return int diffPoint
diff.getDiffSize();

Обернем результат в Assert и получим готовый тест на проверку внешнего вида нашего приложения:

Assert.assertEquals(diff.getDiffSize(), 0);

После этого сгенерируем картинку с пометками отличий наших Actual и Expected и сохраним его в папку с markedImages:

File diffFile = new File(markedImages+name+".png");
ImageIO.write(diff.getMarkedImage(), "png", diffFile);

Добавим все скриншоты в отчет (в нашем случае это Allure):

//Attach images to report
AllureAttachments.attachScreen(expectedFile.getAbsolutePath(), "Expected: "+name);
AllureAttachments.attachScreen(actualFile.getAbsolutePath(), "Actual: "+name);
AllureAttachments.attachScreen(diffFile.getAbsolutePath(), "Differ: "+name);

Сгенерируем gif изображение из картинок expectedFile, actualFile, diffFile:

File[] filesArray = {expectedFile, actualFile, diffFile};
gifFile = GifSequenceWriter.createGIF(filesArray, resultGifs+name);

GifSequenceWriter — класс, в котором есть метод для генерации gif изображения из массивов файлов. Гифку тоже стоит прикрепить к нашему отчету.

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

Проверка и вывод результатов

Про игнорирование и подмену элементов на странице я уже написал. Также можно придумать набор правил для результатов тестов. Если нет желания сильно заморачиваться с игнорированием или вырезанием элементов, то можно прописать правила типа:
— допустимые различия в пикселях (например, 16 или 2078; мигающий курсор на поле для ввода текста);
— допустимый диапазон в пикселях;
— процентное соотношение несовпадения между скриншотами по формуле: diffPoints / кол-во пикселей в снимке * 100;
— все, что меньше N пикселей, не считать ошибкой.

Ну, и собственно, вывод результата тестов — это одна из главных задач автоматизатора, а особенно если это тесты, которые проверяют верстку. Мы у себя используем Jenkins, в котором генерим Allure отчет со всеми параметрами теста, скриншотами, сделанными в процессе выполнения, gif изображением с отличием, логами браузера, куками и т.д.

Описывать, как настраивать эти дела, думаю, в этой статье не стоит, так как эта тема заслуживает отдельного материала.

Самое главное: выводите значение diffPoints и скриншоты — такой отчет уже будет очень полезен :)

Ну и засыпайте всех алертами на почту — это стимулирует фиксить тесты и баги :)

Настоящий автоматизатор должен стремиться к автоматизации всех процессов, которые ему приходится делать руками ©

Вот собственно пока все! Надеюсь, было интересно!
«Стабильных» всем тестов и спасибо за внимание!

Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

👍ПодобаєтьсяСподобалось1
До обраногоВ обраному1
LinkedIn

Схожі статті




49 коментарів

Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.

Оригінально
Але є сумніви, щодо ефективності:
1) замість заморочок з локаторами, тепер заморочки з скріншотами і ’фільтрами’
2) вірогідність помилки в тесті, бо точні asserts замінюються неточними... В коді ’asset actual == expected ’ важче помилитися, ніж в конфігурації евристики порівняння скріншотів.

Тому чим простіше сайт, логіка, тим краще для нового підходу.

Ну и засыпайте всех алертами на почту — это стимулирует фиксить тесты и баги :)

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

3. Далее вызывается метод для сравнения картинок (только что сделанного и эталонного снимков) и выдает результат — различие между ними в пикселях;

По поводу 3 я бы рекомендовал использовать более робастные данные. Например включил бы размытие картинки и сравнивал уже размытые картинки (ну или в каждой точке вычислял бы SURF дескриптор и уже их бы сравнивал), причем вычислял бы порог срабатывания в различие в 5%. Это позволит избежать проблемы смещения части скриншота на 1 пиксел и падения теста.

Шановні, поділіться, будь ласка, як ви реалізовували методи GifSequenceWriter.createGIF та setIgnoredElements ?
Дякую!

та setIgnoredElements ?

я бы делал им visibility: hidden перед снятием скриншота.

Может кто сталкивался? При запуске тестов локально, все хорошо работает. Но есть запускать через Jenkins, скриншоты сохраняются просто как черный экран. Подскажите, в чем может быть проблема?

Случайно заказчик посоветовал, screenster.io
Скажу чесно, даже не пробовал его, поэтому и не могу рекомендовать. Если кто пробовал, напишите

Гениально!!! Не думала, что такое возможно! Но идея просто супер!!!

Очень полезная статья, спасибо автору

У вас функциональные ui тесты и «ашот» тесты живут вместе в одно проекте?
Если да, то:
У вас переиспользуются элементы для этих тестов?
Как параллелите функциональные ui тесты и «ashot» тесты?

Спасибо за приятную и полезную статью!

Да, живут вместе)
Да, переиспользуются + много «другого» кода из проекта используется в этих тестах.
TestNG параллелит на ура)

В тестировании я работаю уже более 6 лет
накопил очень большой опыт

Неужели тестирование — такая простая штука, что всего за 6 лет можно стать супер опытным тестировщиком? Или это особенность отечественного айти?
Ничего не имею против Алексея, просто замечание

6 лет разве этого мало для большого опыта. Это вам не DataArt у которых за 2.5 года становятся senior’ами.
Для описанной статьи и умений которые были освещены, срок в 6 лет — в полне сносно сказать, что у автора большой опыт в ui автоматизации

6 лет в аутсорсе ето уже QA директор

представил, как команда qa директоров под руководством chief qa officer тестирует сайтик

На толковом проекте и CEO и даже рядовой программист будут тестировать свой сайт.
В стремлении сделать качественный продукт — нет ничего зазорного.
Суть не в лейблах и количестве опыта, а в команде и продукте который она делает.

Неужели тестирование — такая простая штука, что всего за 6 лет можно стать супер опытным тестировщиком?

Замечание от чувака который еще студент. Круто.

6 лет для изучения космоса — капля в море.
А вот для освоения профессии вполне нормальный срок.
Все люди разные: Кто-то книгу прочитать может за час, кто-то за 2 недели, а кто-то будет пиво пить вместо этого.

Согласен, слово «очень» в данной фразе лишнее, но вся суть в теме статьи, а не в авторе)

Ну и 6 лет это не такой уж и маленький отрывок времени))

У Вас ошибка в логике теста.
Конкретно на этапе

2. Если отсутствует эталонный снимок, то сделанный скриншот сохраняется в папку с «expected» скриншотами.

Неточность в терминологии. То что Вы называете эталонными снимками, принято называть мастер образами.

И я бы сказал что логика сравнения тоже с ошибкой. И ошибка в том что сравнение неполное.
Да и способ генерации дифов не особо удачный. Мелкие изменения в пиксель сложно найти и легко пропустить.

Ну и напоследок, не уделили внимания именованию директорий. Старые скриншоты иногда бывают полезны, например историю бага посмотреть или откатить все эталонные снимки до какого-то числа.

Думаю терминология «эталонный снимок» довольно близка и понятна людям которые занимаются тестированием. «мастер образ» — не используем в рабочем сленге по отношению к скриншотам, в различных кругах, может быть принято по разному называть это)

В чем заключается ошибка в логике сравнения и его полноте? Тут я вас не сильно понял.

Пропустить тяжело, так как у вас тест будет «завален», если отличие будет даже в пиксель (в зависимости от того как вы наконфигурируете проверки).
+ Мелкие изменения в «пиксель» можно выделять отдельной рамкой на скриншоте — если уж сильно хотите.

Директории именовать можно как вам угодно. В данном случае у нас нет потребности смотреть все эталонные снимки месячной давности. Так же — если такая потребность возникает то в дженкинсе можно настроить хранение результатов сборки со всеми скриншотами и логами. А так будет слишком много места занимать большое количество скриншотов. Но никто не запрещает этого делать, если у вас есть такая потребность.

«откатывать» к конкретному числу или изменениям потребности никогда не возникало, ну и что бы переделать все снимки достаточно запустить тест с параметром для переделывания скриншотов, либо удалить директорию с конкретными снимками — конкретного теста.

Каждый пишет код под потребности своего проекта, со своим Блэк-джеком и скриншотами.

Я попробую объяснить. То что Вы описали не имеет ничего общего с автоматизацией тестирования, это просто выполнение мануальных тестов с использованием софта.
Разница между автоматизированными и мануальными тестами очень простая. Комп может анализировать сотни параметров, а человек нет.

Элегантный и правильный способ, это сохранять html код, css, js либы, вывод js консоли и только потом скриншот.
Прогонять это все через преобразователи. Вытягивать и вырезать дебаг инфу из html и сохранять отдельно, Какие-то тексты заменять (например текущую дату или время) на нули или что-то другое. Можно накладывать маски на скриншоты (белые, черные все равно какие прямоугольники) если софт не умеет с работать с масками. Чем-то это похоже на ETL (Extract, Transform, Load).
Вот этот весь набор преобразованных или оригинальных файлов и будет мастер образом.

На этапе сравнение надо использовать что-то типа приоритетов, задавать порядок сравнения.
Если валяться ошибки в консоль, то как правило скриншот не надо, он просто ничего не покажет. Это или проблема js либ, или проблема в html.

2. Если отсутствует эталонный снимок, то сделанный скриншот сохраняется в папку с «expected» скриншотами.

Автоматические тесты никогда не должны менять мастер образы. Только человек после проверки это должен делать. Тест свалиться с ошибкой «отсутствует мастер образ» — это поведение правильное, в отличии от сохранения мастер образа и выставления статуса PASS.

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

Да и с местом не понятно, терабайты дешевые, как минимум результаты за неделю можно хранить.
Да и опять таки вопрос, куда место девается. Нужно же сохранять только мастер образы, и результаты FAIL тестов.

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

Ну и напоследок, выбор png для скриншотов не особо понятен. Зачем использовать формат с компрессией.

бо это компрессия без искажений?

ожидал, что по линке будет что-то про слоупока — бо не глянул на дату перед тем, как коммент писать :)

попробуйте прикрутити Allure для виводу результатів... в мене всі вище описані підходи працюють в купі з Allure + є можливість компарити скріни з 2-ох енвайрментів, при тому тести на енв. паралеляться, або робити порівняння з попередньо збереженими скрінами:
www.screencast.com/t/mSWS76zVW6

Вы не дочитали до конца)

Мы у себя используем Jenkins, в котором генерим Allure отчет со всеми параметрами теста, скриншотами, сделанными в процессе выполнения, gif изображением с отличием, логами браузера, куками и т.д.

А не простіше було тупо зробити анімацію з трьох кадрів: те що було, те що стало, і накладення 50/50. Річ у тому, що зміни — то нормальна річ, і замість того щоб городити assert — якщо зміни є, тупо відправляти цю GIFку автору і нехай сам дивиться чи те що змінилося нормально, чи ні.

Цим вирішується проблема: не потрібно переписувати тест під нову фічу. Мало того, можно це відправити замовнику і спитати чи цей результат той що він хотів, чи ні. І цим зекономити час на розмови.

це аля CSS checker — ассерт як раз і покаже ту зміну, якшо 500 скріншотів і з них тільки 2 мають зміни, то манагер має відкрити всі 500 і шукати де є відмінність ?

Ні. Автоматика співставить зображення грубо, а вже де знайде відмінність — там скріншоти. Тобто на виході звичайна собі html сторінка, із вказанням місця та скріншота. Можна навіть гіфку не робити, а просто покласти елементи один над одним та натисканням кнопаря перемикати.

Шо з чим співставить ? Де береться actual i expected result ? Яка ше html сторінка на виході ?

Основная суть автоматизации тестирования именно в автоматизации тестирования)
Так конечно применений много можно придумать, ваш вариант тоже подойдет. Но если мы говорим о тестах, а тем более о автотестах — то хотелось бы максимально этот процесс автоматизировать)
+ Как уже писали ниже — если очень много скриншотов то человеку будет тяжко с таким количеством справится, а так же мелкие ошибки глазом бывает гораздо сложнее заметить.

просто маску делали тулзы для автомаизации еще в середине 90-х. Тогда правда цветов было поменьше на мониторах и проще было пиксели сравнивать.

Хорошая статья! Спасибо за материал.

Ідея цікава. Фактично в статті описується як зробити регресійне тестування GUI.
Нажаль, на практиці не все так просто, як описується в теорії, тому підготував декілька питань до автора:
1. Повноцінне тестування всіх можливих варіантів вигляду сторінок під різними операційними системами, браузерами та їх версіями, роздільною здатністю, відмінності в конфігураціях в веб додатках на різних інваєрментах і так далі призводить до проблеми великої кількості тестових стендів, швидкості прогону тестів, та великої кількості інформації яку потрібно зберігати та підтримувати. Як вирішити цю проблему на практиці?
2. Як пітримувати очікувані скріншоти в актуальному стані, при активній розробці продукту?
3. В статті пропонується використати Selenium Webdriver, щоб попасти на потрібні сторінки. Якщо робити скріншоти постійно після кожної зміни URL, ми будемо мати багато дубльованих скріншотів. Можливо було б краще, використовувати павуків? Але як тоді вирішувати проблему фонової інформації (попапи, динамічно змінююча інформація, тощо)?
4. Яке ROI він такої автоматизації? Чи є взагалі сенс в такій автоматизації, якщо урахувати затрати інженера, підтримку своїх тестових інваєрментів на серверах або плату за cloud системи, такі як SauceLabs, Browserstack, Testingbot?

Дякую за відповіді завчасно.

Все працює на ура, сам юзає все вище описане, правда трохи результат по іншому виводжу

1. Сервера, либо облачные решения которые вы упомянули в 4м пункте. Количество связок зависит от требований вашего продукта.
2. Делать упор на снимки элементов, а не страниц. Так же можно просто периодически «переснимать» заново все эталонные снимки. (После запланированных изменений).
3. Кол-во скриншотов зависит от пункта 1.
Про «пауков» не понял, можно поподробнее ?)
Фоновая информация — вырезаться \ игнорируется. Если нужно тестировать ее — можно написать отдельный набор тестов для этих вещей (но не уверен насчет целесообразности данного действа)
4. Вопрос довольно философский) «такая» автоматизация не отличается от «обычной» — все метрики и затраты — будут ровно такими-же как и при написании и поддержании тестов «не для верстки». Сложность поддержки тестов зависит от знаний человека который пишет эти тесты.
По поводу ROI вспомнилось обсуждение — automated-testing.info/t/roi/1608

Отличная статья, спасибо! Если хотите попробовать похожий инструмент как SaaS решение — есть наш backtrac.io. Мы для сравнение используем свой алгоритм, который распознает смещения элементов. Соответственно у вас не будет закрашиваться вся страница красным, если был сдвиг где-нибудь в хедере.

Пользуемся этим же «оружием» на текущем проекте. Очень полезная вещь. Подробно и доступно написано, спасибо)

Полезная статья

моя почта находится в профиле
Точно?)

Что думаете по поводу backstopjs?

Не сталкивался с этом инструментом. Но думаю в нем есть пару но:
1. Работает только с веб страницами, в отрыве от них таким инструментом не попользуешься.
( например для мобильных или десктоп приложений, флеша )
2. У нас весь код проекта с тестами написан на джаве и львиную долю написанного кода можно использовать и для тестов верстки, соответственно нет заморочек с логированием, репортингом, элементами на страницах и т.д.

Підписатись на коментарі