Что такое snapshot тесты
Что проверяют
Понимаете ли вы, что именно ловят снимки и чем вы платите за них в поддержке. Следом обычно спрашивают, как сделать их стабильными в CI и что происходит, когда изменение интерфейса запланировано.
Как отвечать
Snapshot-тест рендерит экран или компонент в заданном состоянии и сравнивает результат с эталоном, сохранённым в репозитории. Первый прогон записывает эталон, последующие сравнивают и при расхождении падают, прикладывая эталон, текущий снимок и разницу.
- инструменты: на iOS стандарт де-факто это
swift-snapshot-testingот Point-Free. СтарыйiOSSnapshotTestCase(бывшийFBSnapshotTestCase) встречается в легаси-проектах; - стратегии: не только картинка.
assertSnapshot(of: vc, as: .image)сравнивает пиксели,.recursiveDescriptionсравнивает дерево вью текстом,.dumpи.jsonфиксируют модель или ответ сервера; - SwiftUI: вью оборачивают в
UIHostingControllerили снимают напрямую с явной раскладкой под конкретное устройство; - матрица состояний: светлая и тёмная тема, крупный Dynamic Type, RTL, пустой список, ошибка. Здесь снимки и окупаются: вручную такие комбинации никто не перебирает;
- обновление: при запланированном изменении эталоны перезаписывают в режиме записи и коммитят вместе с кодом, а ревьюер смотрит разницу картинок в PR.
Место в пирамиде тестов: снимки дёшево ловят визуальные регрессии, но не проверяют логику и навигацию. Для этого остаются unit-тесты и XCUITest.
Где спотыкаются
Не фиксируют окружение. Рендер зависит от модели симулятора, версии iOS и масштаба экрана, поэтому эталоны снимают на том же симуляторе, что и в CI, иначе тесты краснеют на ровном месте. Мелкие расхождения сглаживает параметр precision у стратегии .image.
Оставляют в снимке живые данные: текущую дату, анимации, картинки из сети. Всё недетерминированное подменяют заглушкой до рендера.
Перезаписывают эталоны вслепую, как только тест упал. Так баг попадает в эталон и дальше защищается тестом. Упавший снимок сначала открывают и смотрят разницу.