Хабр, привет! Меня зовут Борис. Я AQA iOS-engineer в Vivid Money. В этой статье я хочу рассказать про snapshot тесты и показать, как их можно эффективно применять в своём проекте. Данная статья будет полезна начинающим iOS-автоматизаторам, либо разработчикам, которые решили изучить XCUITest и покрыть свой проект ui-тестами. В рамках статьи мы разберем: Что такое snapshot тесты и когда их применять. Какие есть библиотеки. Поэтапно расскажу и покажу как внедрить их у себя в проекте. Snapshot тесты — это тесты, которые делают скриншот экрана (эталонный скриншот) и сравнивают с актуальным скриншотом, который делается во время прогона тестов. Делать Snapshot тесты на все возможные проверки — плохая практика, так как если будет редизайн, ваши тесты моментально станут красными, и вам придется в срочном порядке менять эталонные скриншоты. Я советую использовать Snapshot тесты для проверки верстки, элементов, с которыми тяжело взаимодействовать по accessibilityidentifier (график цен, календарь и прочие). В основном, при написании Snapshot тестов используют две библиотеки: iOSSnapshotTestCase (previously FBSnapshotTestCase). SnapshotTesting. Их основные различия: Фичи iOSSnapshotTestCase SnapshotTesting Язык реализации фреймворка Objective-C Swift Diff скриншоты Есть Есть Скриншоты любого UI-элемента Нужно реализовывать самому Есть Гибкая настройка погрешности совпадения скриншотов 2 параметра 1 параметр Последняя дата обновления фреймворка 12 октября 2019 27 апреля 2021 Поддерживает менеджеры зависимостей CocoaPods, Carthage CocoaPods, Carthage, Swift Package Manager Перед выполнением разделов ниже, нужно сделать следующее: Добавить таргет ui-тестов в проект. Как это сделать, можно посмотреть в статье в разделе "Настраиваем среду". Установить библиотеку iOSSnapshotTestCase и настроить переменные. Инструкция есть в репозитории. Разберем все поэтапно: Для начала нам нужно импортировать скачанную библиотеку и наследоваться от класса FBSnapshotTestCase, чтобы появился доступ к нужным методам. Теперь нам нужно добавить метод для записи скриншота, чтобы мы могли использовать его в любой момент выполнения тестового сценария ui-тестов. Разберем, что мы делаем в методах выше. Обратите внимание на Tolerance. Tolerance — это допустимое отклонение актуального скриншота от эталонного. Рассчитывается по шкале от 0 до 1, где  = 0,05 - равно 5%. По дефолту аргументы: perPixelTolerance и overallTolerance = 0%. overallTolerance — допустимое отклонение общего количества пикселей; perPixelTolerance — допустимое отклонение каждого пикселя. Для наглядности покажу пример: Зачастую снэпшот тесты используют для прогона на разных девайсах и версиях ОС. Для этого нужно, чтобы название эталонных скриншотов отличалось. Библиотека позволяет это делать. Для этого в setUp мы добавляем кусок кода ниже: На данный момент мы можем сформировать имя скриншота из 4 параметров: FBSnapshotTestCaseFileNameIncludeOption.device — тип девайса (iPhone, iPad и так далее). Берётся из UIDevice.currentDevice.model. FBSnapshotTestCaseFileNameIncludeOption.OS — версия операционной системы. Берётся из UIDevice.currentDevice.systemVersion. FBSnapshotTestCaseFileNameIncludeOption.screenScale — масштаб экрана. Берётся из UIScreen.main.scale. FBSnapshotTestCaseFileNameIncludeOption.screenSize — размер экрана. Берётся из UIApplication.sharedApplication.keyWindow.bounds.size. Для записи эталонного скриншота вам понадобится свойство recordMode. Если recordMode = true, мы формируем эталонный скриншот, либо перезаписываем старый; Если recordMode = false, мы сверяем текущий скриншот, который делается во время прогона с эталонным. Добавляем его в setUp(), чтобы записать эталонный скриншот для теста, и присваиваем ему значение = true. Теперь пишем сам тест: Тест отобразится с статусом failed. В описании ошибки будет информация, что эталонный скриншот сформирован. Теперь изменим значение recordMode на false, чтобы проверить, что наш тест правильно отрабатывает. Тест отобразился с статусом passed. Поздравляю! Вы написали свой первый Snapshot тест. Свойство recordMode по умолчанию false, поэтому после записи эталонного скриншота можете удалить его из метода setUp. Но есть одна проблема, которая может разрушить наши планы по покрытию приложения снэпшотами — Status bar. В нем отображается заряд батареи и время, которые не статичны! В разделе ниже мы разберем способы, как это одолеть. Эту проблему можно решить, отрезав на скриншоте Status bar. Основная проблема в том, что начиная с iPhone серии «X» у нас нестандартный размер Status bar: Модель устройства Высота Status Bar iPhone XS Max, iPhone 11 Pro Max, iPhone X, iPhone XS, iPhone 11 Pro, iPhone 12 Pro Max, iPhone 12 Pro 132 px iPhone XR, iPhone 11, iPhone 12 88 px iPhone 6 Plus, iPhone 6S Plus, iPhone 7 Plus, iPhone 8 Plus 54 px iPhone 6, iPhone 6S, iPhone 7, iPhone 8, iPhone 5, iPhone 5S, iPhone 5C, iPhone SE, iPhone 4, iPhone 4S 40 px Для этого напишем два расширения: UIDeviceExtension — будем определять текущий девайс. UIImageExtension — будем обрезать status bar для девайса. Теперь нам достаточно в методе verifyView() добавить свойство removingStatusBar. Мы разобрались, как написать снепшот тест. Если тест не прошел, то в отчете будет следующее: У нас есть 3 скриншота: Reference Image — эталонный скриншот, который мы сделали в надежде, что так будет выглядеть экран приложения всегда (ожидаемый результат); Failed Image — актуальный скриншот экрана во время прогона теста (фактический результат); Diffed Image — наложение эталонного скриншота на актуальный. На нем мы можем видеть, что именно изменилось на экране. Используйте Snapshot тесты для проверки верстки, элементов, с которыми тяжело взаимодействовать по accessibilityidentifier; Используйте библиотеку iOSSnapshotTestCase, если поймете что его функционала вам мало, перейдите на SnapshotTesting; Для достоверных результатов используем overallTolerance = 0,05; если выставите больше, Snapshot тесты не будут достаточно достоверными. Snapshot тесты — это классный инструмент для повышения качества вашего продукта, но важно его использовать с умом. Не все кейсы стоит покрывать снэпшотами. Тестовый проект с снэпшот тестами можете посмотреть в моём репозитории. Вдохновлялся статьями: Snapshot testing in Swift Snapshot XCUITestin Интересуешься автоматизацией на iOS? Подписывайся на мой телеграмм-канал, в котором я публикую материалы, которые будут полезны как начинающим, так и опытным iOS-автоматизаторам. AQA Lead & SDET