Snapshot-тестування — це автоматичний контроль того, що UI не змінився незаплановано. Розробник править відступ в одному компоненті, забуває про екран налаштувань, де той самий компонент використовується з іншими пропсами — і через тиждень у продакшені виявляється з'їхавша верстка. Snapshot-тест зловив би це за секунди. Ми впроваджуємо такі тести під ключ: налаштовуємо інструмент, пишемо тести для ключових компонентів та інтегруємо перевірку в CI. Це економить години ручних перевірок та запобігає регресіям.
Чому snapshot-тести критичні для мобільного застосунку?
Без автоматичної верифікації UI будь-яка зміна стилів або компонентів може призвести до візуальних багів, які не ловляться модульними тестами. Ручний перегляд екранів перед релізом — повільний і ненадійний. Snapshot-тести вирішують проблему: один запуск — 100% перевірка всіх екранів.
Суть проста: при першому запуску тест зберігає еталонне зображення або серіалізоване дерево компонентів. При кожному наступному запуску порівнює з еталоном. Розбіжність = падаючий тест.
Порівняння інструментів snapshot-тестування
| Платформа | Інструмент | Середній час тесту | Підтримка Compose/SwiftUI |
|---|---|---|---|
| iOS | swift-snapshot-testing | 1–3 сек | SwiftUI (через UIView) |
| Android | Paparazzi | 200–500 мс | Jetpack Compose |
| Flutter | Golden Tests | 0.5–1 сек | Flutter Widget |
Paparazzi в 20 разів швидше, ніж screenshot-тести з емулятором: 200 мс проти 6 секунд на тест. Для бібліотеки на 200 компонентів різниця 30 хвилин проти 3 хвилин.
iOS: iOSSnapshotTestCase
На iOS snapshot-тести будуються на pointfreeco/swift-snapshot-testing (колишній FBSnapshotTestCase). Це найбільш зріле рішення:
import SnapshotTesting class ProfileViewControllerTests: XCTestCase { func testProfileScreen() { let vc = ProfileViewController(user: .mock) assertSnapshot(of: vc, as: .image(on: .iPhone13Pro)) } func testProfileScreenDarkMode() { let vc = ProfileViewController(user: .mock) assertSnapshot(of: vc, as: .image(on: .iPhone13Pro(.landscape), traits: .init(userInterfaceStyle: .dark))) } } assertSnapshot при першому запуску створює файл __Snapshots__/ProfileViewControllerTests/testProfileScreen.1.png. При наступних — порівнює піксель за пікселем. Поріг — 0, будь-яке відхилення = fail.
Підтримувані стратегії знімка: .image (скріншот), .recursiveDescription (текстове дерево view), .dump (структура). Для компонент-бібліотек .image — основна.
Проблема зі шрифтами в CI
Рендеринг тексту на симуляторі може відрізнятися від рендерингу на CI-машині через різні версії системних шрифтів. Рішення — фіксувати симулятор (iPhone 15, iOS 17.4) і використовувати одну й ту саму версію Xcode. У fastlane через xcversion:
xcversion(version: "~> 15.3") Android: Paparazzi
Для Android найкращий інструмент — Paparazzi від Square. Він не потребує емулятора: рендерить View через LayoutInflater у JVM-середовищі, використовуючи layoutlib (той самий двигун, що й Android Studio Preview).
class ButtonSnapshotTest { @get:Rule val paparazzi = Paparazzi( deviceConfig = DeviceConfig.PIXEL_6, theme = "Theme.App" ) @Test fun primaryButton() { paparazzi.snapshot { PrimaryButton( text = "Зберегти", onClick = {} ) } } } Запуск: ./gradlew recordPaparazziDebug (запис еталонів) та ./gradlew verifyPaparazziDebug (перевірка).
Paparazzi підтримує Jetpack Compose з paparazzi.snapshot { ComposableFunction() } — та сама механіка.
Flutter: Golden Tests
У Flutter snapshot-тести називаються Golden Tests і є частиною flutter_test:
testWidgets('CustomCard golden', (tester) async { await tester.pumpWidget( MaterialApp(home: CustomCard(title: 'Test', subtitle: 'Subtitle')), ); await expectLater( find.byType(CustomCard), matchesGoldenFile('goldens/custom_card.png'), ); }); Оновлення еталонів: flutter test --update-goldens.
Платформозалежність golden-файлів — відома проблема. macOS рендерить шрифт інакше, ніж Linux (CI). Рішення: зберігати golden-файли, згенеровані на CI (Linux), а локально розробники використовують flutter test --update-goldens лише на тій самій ОС. Або пакет golden_toolkit з loadAppFonts(), який нівелює частину відмінностей.
Як snapshot-тести інтегруються в CI?
Ми налаштовуємо CI-пайплайн так, щоб у ньому виконувалася лише верифікація (verify), а запис еталонів відбувався локально. Це гарантує, що зміни UI не прослизнуть непоміченими.
Типові причини розбіжностей на CI
- Різні версії шрифтів
- Різний рендеринг на симуляторі та CI-машині
- Роздільна здатність екрану та масштаб
- Версії Xcode та SDK
Рекомендується фіксувати середовище та запускати запис еталонів на тому самому середовищі, де буде CI.
Приклад з нашої практики
Для одного з проектів (клієнт — fintech-сервіс) ми впровадили snapshot-тести на Flutter. Компонентна бібліотека містила 120 віджетів. Після налаштування golden-тестів час регресійного тестування UI скоротився з 2 годин ручного перегляду до 3 хвилин автоматичної перевірки. Всі еталонні знімки зберігаються в репозиторії та оновлюються лише усвідомлено.
Що входить в роботу
- Аналіз поточної UI-архітектури та вибір інструменту
- Налаштування інструменту snapshot-тестування (iOS/Android/Flutter)
- Написання тестів для ключових екранів та компонентів (10–30 тестів)
- Інтеграція в CI (GitHub Actions, GitLab CI або Bitrise)
- Документація з роботи зі знімками та процесу оновлення
- Навчання команди (1–2 години)
Управління базовими знімками в git
Еталонні знімки зберігаються в репозиторії. Кілька правил:
-
__Snapshots__/,src/test/snapshots/,test/goldens/— додаємо в.gitattributesяк бінарні:*.png binary - Pull Request зі зміною UI повинен включати оновлені знімки:
git add test/goldens/ && git commit -m "update snapshots" - У CI запускаємо лише перевірку (
verify), не запис (record). Запис — лише локально або через спеціальний workflow
Якщо CI падає через розбіжність знімків — це не помилка тестів, це сигнал про незаплановану зміну UI. Добре.
Строки та вартість
2–3 дні — налаштування інструменту + написання snapshot-тестів для ключових компонентів. Повне покриття компонентної бібліотеки (50+ компонентів) — оцінюємо окремо. Вартість розраховується індивідуально. У нас 5 років досвіду в мобільній розробці та понад 30 проектів з автотестами — гарантуємо якість та дотримання строків.
Замовте впровадження snapshot-тестів вже сьогодні — отримайте консультацію по вашому проекту. Зв'яжіться з нами для оцінки — ми підберемо оптимальний інструмент та складемо план впровадження.







