Что такое snapshot-тестирование в iOS и как его реализовать?

«Что такое snapshot-тестирование в iOS и как его реализовать?» — вопрос из категории Тестирование, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Snapshot-тестирование (тестирование снимками) — это метод UI-тестирования, при котором визуальное состояние интерфейса (компонента или экрана) сравнивается с заранее сохраненным эталонным изображением (снимком).

Основные библиотеки и подходы:

  1. iOSSnapshotTestCase (бывший FBSnapshotTestCase): Классическая библиотека для UIKit.
  2. SwiftUI SnapshotTesting (Point-Free): Современная и гибкая библиотека, поддерживающая не только изображения, но и текстовые представления.
  3. Встроенный assertSnapshot (Xcode 15+, iOS 17+): Нативное решение для SwiftUI.

Пример для UIKit с iOSSnapshotTestCase:

import iOSSnapshotTestCase

class CustomButtonSnapshotTests: FBSnapshotTestCase {
    func test_primaryButtonState() {
        let button = CustomButton()
        button.configure(with: .primary)
        button.frame = CGRect(x: 0, y: 0, width: 200, height: 50)

        // Делает снимок и сравнивает с эталоном в папке ReferenceImages_
        FBSnapshotVerifyView(button)
    }
}

Пример для SwiftUI с библиотекой SnapshotTesting:

import SnapshotTesting
import SwiftUI

func test_contentView() {
    let view = ContentView(viewModel: .mock)
    // Сравнивает рендер вью как изображение с эталоном.
    assertSnapshot(of: view, as: .image)
}

Ключевые практики:

  • Изоляция: Тестируйте компоненты в чистом, предсказуемом состоянии.
  • Покрытие состояний: Фиксируйте снимки для всех ключевых состояний (загрузка, ошибка, пустое состояние, разные данные).
  • Стабильность: Используйте фиксированные размеры устройств, версии ОС и локали для воспроизводимости.
  • Tolerance: Настраивайте допуск (perceptualPrecision) для различий в антиалиасинге и рендеринге на разных симуляторах.
  • CI/CD: Эталонные снимки должны храниться в репозитории и обновляться при преднамеренных изменениях UI.