В первой части мы рассмотрели первую партию библиотек для скриншот-тестирования, сейчас настало время для обзора оставшихся библиотек, среди которых: Roborazzi Android Testify Snappy (Kotlin snapshot testing) Следующей в нашем списке идет библиотека Roborazzi. Это интересная попытка с новой стороны подойти к реализации той же идеи, что была заложена в Paparazzi - ускорить скриншот-тестирование путем запуска тестов не на устройствах Android, а на JVM. Здесь для создания скриншотов используется Robolectric, в котором с недавних пор появился новый графический режим - Native. Robolectric поставляется с набором моков для классов из Android SDK, но с новым режимом графический код будет выполняться на реальных классах из Android OS. Благодаря этому мы получаем преимущества Paparazzi в виде высокой скорости выполнения тестов, но без его недостатков. Так, поскольку библиотека не завязывается на парсинг ресурсов, Roborazzi может использоваться не только в библиотечных модулях, но и в application-модуле. Помимо этого отсутствует ограничение на создание скриншотов всей activity, так как захват скриншотов происходит непосредственно с "экрана". Интеграция библиотеки в проект как водится начинается с подключения Gradle-плагина и необходимых зависимостей: В самом тесте необходимо включить поддержку нативной графики: Roborazzi предоставляет два варианта написания тестов. При использовании RoborazziRule скриншоты для тестов будут созданы автоматически: Либо можно вручную вызывать метод captureRoboImage() для создания скриншотов: Для запуска тестов мы используем gradle-таски, предоставляемые библиотекой: Основная разница между compareRoborazziDebug и verifyRoborazziDebug заключается в том, что verifyRoborazziDebug бросит исключение в том случае, если скриншот изменился, а compareRoborazziDebug просто произведет сравнение двух изображений. В случае расхождения между полученным скриншотом и референсом Roborazzi создаст diff-изображение: В целом, идея библиотеки очень интересная, но у неё еще много детских болячек, таких как скудная или отсутствующая документация, местами странный API и спорные архитектурные решения. Например, файлы из текущего прогона и diff-изображения, которые по сути являются временными файлами, создаются внутри папки с референсами вместо того, чтобы использовать для них папку build. Но библиотека активно развивается, что дает надежду на решение этих проблем. Использование Robolectric хотя и позволяет выйти за рамки ограничений, присущих Paparazzi, но приносит свои проблемы типичные для Robolectric. Также стоит отметить, что Roborazzi использует для сравнения изображений библиотеку Differ от Dropbox, которая используется в рассмотренной нами в первой части библиотеке Dropshots.   Разработка этой библиотеки стартовала в компании Shopify еще в конце 2018 года, однако сейчас продолжается в отдельном репозитории. Testify работает по той же схеме, что и Dropshots - сравнение изображений выполняется непосредственно на устройстве во время прогона тестов. Для этого референсные изображения сохраняются в папке androidTest/assets, что позволяет упаковать их в тестовый apk и запустить сравнение локально.  Интеграция в проект требует подключения Gradle-плагина: В самих тестах вместо обычного ActivityScenarioRule следует использовать ScreenshotRule, тестовый метод необходимо пометить аннотацией @ScreenshotInstrumentation и затем вызвать метод assertSame: Для запуска тестов мы можем использовать Gradle-task screenshotTest, но также сгодится и стандартный таск Android connectedCheck. Помимо этого у Testify есть свой плагин для Android Studio, с которым запуск теста возможен непосредственно из сайдбара в IDE: С помощью этого плагина еще можно запустить задачи для создания референсного скриншота, загрузки и удаления всех скриншотов с девайса. Testify предоставляет несколько групп Gradle-тасков: По умолчанию в Testify отключена генерация diff-изображений, но если мы хотим её включить, то это можно сделать одним из трех способов. Либо в глобально для всех тестов в манифесте: Для всего тестового класса:  Или же для одного тестового метода при помощи ScreenshotRule: В этом случае при возникновении регрессии Testify создаст так называемый High‑Contrast diff, где каждое изменение, неважно насколько значительное, будет отмечено красным цветом. В общей сложности diff‑изображение может содержать 4 цвета:  красный — для измененных областей изображения; серый — для областей, исключенных из сравнения; желтый — измененные области, но в пределах заявленной погрешности; черный — неизменные области. В целом это выглядит следующим образом: В целом стоит отметить, что библиотека Testify лично мне кажется наиболее проработанной и гибкой, поддерживающей различные сценарии тестирования и решающей различные проблемы, с которыми сталкивается каждый, кому приходится заниматься таким неблагодарным делом как инструментальное тестирование Android. Так, в отличие от других библиотек Testify создает отдельную папку для каждой конфигурации тестового устройства, например:  Кроме этого ScreenshotRule позволяет передавать аргументы для активити, в которой будут запускаться тесты: А также произвести какие-то манипуляции перед тем, как произвести скриншот-тестирование: Или же остановить выполнение тестов для анализа верстки при помощи метода setLayoutInspectionModeEnabled(true). Кроме того ScreenshotRule дает возможность поменять в тесте локаль, масштабирование шрифтов, ориентацию экрана, либо запросить фокус на каком-либо элементе экрана. По умолчанию Testify захватывает весь экран при создании скриншота, но также возможно создание скриншота только для какого-то определенного View или же исключение области экрана из сравнения: Также разработчики предоставляют возможность кастомизировать метод для создания скриншотов и их рендеринг. По умолчанию в Android используется аппаратное ускорение для рендеринга интерфейса, в результате чего мы можем получить определенным образом различающиеся скриншоты при использовании различных устройств. На результат влияют как различия в CPU, так и GPU, тип видеокарты (дискретная или встроенная) и другие факторы. Отличия могут возникнуть в следующих участках: антиалиасинг и сглаживание шрифтов; тени и elevation; области с прозрачностью. Для того, чтобы нивелировать подобные различия существует несколько способов, самым простым из которых является использование одной и той же конфигурации для тестирования. Однако зачастую это невыполнимая задача: внутри одной команды разработчики могут вести разработку на ЭВМ, использующих различные процессорные архитектуры, видеокарты, использование различных CI сервисов также вносит свою долю неопределенности. Другим вариантом является отключение аппаратного ускорения для тестов. Testify позволяет отключать аппаратное ускорение для определенных тестов: Стоит упомянуть о том, что Testify дает возможность использовать различные методы для создания скриншотов. По умолчанию из соображений обратной совместимости используется метод View.getDrawingCache(), но возможно использование рендеринга на Canvas при помощи метода View.draw(), однако наиболее предпочтительным является использование API PixelCopy, поскольку в этом случае скриншот создается из Surface, что позволяет корректно сохранить в скриншоте элементы, которые зависят от аппаратного ускорения. Включить нужный метод создания скриншота с использованием способами, аналогичными включению генерации diff-изображений, с с использованием соответствующих TestifyFeatures:  CanvasCapture PixelCopyCapture Помимо этого Testify дает возможность игнорировать небольшие различия в изображениях с использованием более продвинутых алгоритмов сравнения, чем простой подсчет количества отличающихся пикселей. Так Testify позволяет считать для скриншотов параметр Дельта E, использование которого является стандартом в цветокоррекции при сравнении двух изображений. Слово "дельта" является стандартным обозначением для различия какой-либо величины. Буква "Е" — это первая буква немецкого слова Empfindung, "ощущение". Дословно понятие обозначает разницу в ощущениях. Testify использует формулу CIE LAB 94 для вычисления Дельта Е Кроме того, Testify предоставляет несколько расширений. Во-первых, это расширение для Compose. Во-вторых, это расширение Accessibility Сhecks, которое добавляет еще один метод для ScreenshotRule - assertAccessibility(). Вызов этого метода будет выполнять набор проверок из Accessibility Test Framework. Также благодаря выполнению тестов на девайсе Testify можно использовать с Firebase Test Lab: референсы скриншотов упаковываются в тестовый apk и доступны на устройстве. Также решена проблема со скачиванием референсов и diff-изображений с девайса. Если Dropshots использует для этого adb, который не работает на FTL, то Testify специально для таких случаев позволяет использовать SD Card для записи скриншотов и diff-изображений. Благодаря этому скриншоты, вместе с остальными тестовыми артефактами будут сохранены в Google cloud, откуда их можно скачать вручную, либо, при использовании Flank, автоматически. В целом, несмотря на отдельные недочеты, такие как местами устаревшая документация или неработающие фичи (например, в текущей бете поломан таск по скачиванию отчетов о тестировании, но фикс уже в пути) библиотека Testify выглядит как тот самый грааль скриншот-тестирования. Единственное, чего на мой взгляд не хватает этой библиотеке — это поддержки Gradle managed devices. Последней в нашем списке идет небольшая библиотека Snappy. На данный момент вряд ли имеет смысл затаскивать её в проект — слишком сырой она выглядит. Библиотека написана с использованием Kotlin Mutliplatform, поэтому для того, чтобы её испытать в проект надо подключить несколько зависимостей: Библиотека еще не имеет своего артефакта на mavenCentral и распространяется через Jitpack. Тестовый класс нужно наследовать от AndroidFileSnapshotTest, который предоставляет метод snapshotToFilesDir(). Поскольку метод объявлен как , вызывать его необходимо с использованием вспомогательного метода runTest(): Метод создаст новый скриншот и запустит его сравнение с образцом. В случае, если образца нет, при помощи параметра record = true можно создать референс. Отдельной задачи на запуск скриншот-тестов нет, тесты выполняются в рамках стандартного запуска инструментальных тестов. В случае регрессии будет создано diff-изображение: Функциональность библиотеки в области скриншот-тестов на этом исчерпывается. Само сравнение изображений выполняется на девайсе, но в отличие от Dropshots и Testify, Snappy не пакует референсы в тестовый apk, поэтому перед запуском скриншот-тестирования их надо на девайс загрузить при помощи adb. После прогона тестов опять же при помощи adb нужно скачать diff-изображения или новые референсы. При этом каких-то специальных Gradle-тасков для этого библиотека не предоставляет. Также отсутствует функционал по созданию отчетов о тестировании. К тому же Snappy поддерживает только Compose. В целом, библиотека выглядит как интересная заявка на будущее, особенно с учетом поддержки Mutliplatform, но пока что ей не хватает важных функций для того, чтобы её можно было использовать в своих проектах. На этом мы завершаем рассмотрение различных библиотек для скриншот-тестирования. В заключительной части мы подведем итоги и сравним рассмотренные библиотеки по различным критериям.    Android-разработчик