Основы тестирования iOS
Тестирование iOS требует понимания строго контролируемой экосистемы Apple. В отличие от Android, где производители могут модифицировать ОС, каждое устройство iOS работает на немодифицированной операционной системе Apple.
Жизненный цикл iOS-приложений
Понимание жизненного цикла критично для мобильных тестировщиков, потому что многие баги возникают при переходах между состояниями.
Состояния приложения
Не запущено → Неактивно → Активно → Фоновое → Приостановлено → Завершено
| Состояние | Описание | Фокус тестирования |
|---|---|---|
| Не запущено | Приложение не запускалось или было завершено | Производительность холодного старта |
| Неактивно | На переднем плане, но не получает события | Обработка прерываний |
| Активно | На переднем плане, получает события | Обычная функциональность |
| Фоновое | Выполняет код, но не видимо | Завершение фоновых задач |
| Приостановлено | В памяти, но код не выполняется | Восстановление состояния |
| Завершено | Удалено из памяти | Сохранение данных |
Критические сценарии тестирования
Холодный vs тёплый старт: Замерьте запуск из завершённого состояния (холодный) против приостановленного (тёплый). Пользователи замечают, если холодный старт занимает более 2 секунд.
Прерывания: Проверьте, что происходит при:
- Входящем звонке во время критической операции
- Активации Siri
- Появлении предупреждения о низком заряде
- Срабатывании таймера или будильника
- Открытии Центра управления
Из фона на передний план: После 30+ минут в фоне приложение корректно восстанавливается? Проверьте:
- Истёкшие токены авторизации
- Устаревшие данные на экране
- Потерянный ввод форм
- Разорванные WebSocket-соединения
Давление на память: iOS может завершить приостановленные приложения в любой момент. Тестируйте восстановление состояния после принудительного завершения.
Инструменты тестирования Xcode
XCUITest
XCUITest — нативный фреймворк UI-тестирования Apple, взаимодействующий с приложением через систему доступности.
// Пример XCUITest
func testLoginFlow() {
let app = XCUIApplication()
app.launch()
let emailField = app.textFields["Email"]
emailField.tap()
emailField.typeText("user@example.com")
let passwordField = app.secureTextFields["Password"]
passwordField.tap()
passwordField.typeText("password123")
app.buttons["Sign In"].tap()
XCTAssertTrue(app.staticTexts["Welcome"].waitForExistence(timeout: 5))
}
Xcode Instruments
Instruments — инструментарий профилирования, входящий в Xcode:
| Инструмент | Назначение | Когда использовать |
|---|---|---|
| Time Profiler | Анализ использования CPU | Приложение ощущается медленным |
| Allocations | Отслеживание использования памяти | Высокое потребление памяти |
| Leaks | Обнаружение утечек памяти | Память растёт со временем |
| Energy Log | Потребление батареи | Расход батареи в фоне |
| Network | Профилирование сетевых запросов | Медленная загрузка данных |
Система разрешений iOS
iOS имеет строгую модель разрешений. Приложения должны запрашивать разрешение на доступ к чувствительным ресурсам.
Разрешения для тестирования
| Разрешение | Первый запрос | После отказа | Способ сброса |
|---|---|---|---|
| Камера | Системный диалог | Через Настройки | Настройки > Конфиденциальность > Камера |
| Геолокация | 3 варианта: Однократно, При использовании, Всегда | Только Настройки | Настройки > Конфиденциальность > Геолокация |
| Уведомления | Системный диалог | Только Настройки | Настройки > Уведомления |
| Фото | Диалог с ограниченным/полным доступом | Только Настройки | Настройки > Конфиденциальность > Фото |
Чек-лист тестирования разрешений
- Первый запрос разрешения показывает корректный диалог
- Приложение грамотно обрабатывает отказ (без краша, полезное сообщение)
- Приложение работает с ограниченным доступом к фото (iOS 14+)
- Разрешение геолокации «При использовании» vs «Всегда» работает корректно
- Отзыв разрешения в Настройках не вызывает краш
- App Tracking Transparency (iOS 14.5+) появляется до любого отслеживания
Подготовка к ревью App Store
Apple проверяет каждую отправку приложения. Типичные причины отклонения:
Топ-5 причин отклонения
- Баги и краши (самая частая) — тестируйте все флоу на минимальной поддерживаемой версии iOS
- Битые ссылки и placeholder-контент — проверьте все URL в приложении
- Неполные метаданные — скриншоты должны соответствовать текущему UI
- Проблемы производительности — запуск должен завершаться за разумное время
- Нарушения гайдлайнов дизайна — используйте стандартные паттерны навигации iOS
Чек-лист перед отправкой
□ Протестировано на минимальной поддерживаемой версии iOS
□ Протестировано на последней версии iOS
□ Все диалоги разрешений проверены (выдача и отказ)
□ Dark Mode проверен на всех экранах
□ Dynamic Type проверен (максимальный и минимальный размеры)
□ Базовая навигация VoiceOver работает
□ Нет крашей в логах Xcode Organizer
□ Все ссылки рабочие
□ Privacy manifest обновлён (iOS 17+)
□ Скриншоты соответствуют текущему UI
Упражнение: Охота за багами iOS
Сценарий: Вы тестируете приложение заказа еды на iOS, готовящееся к первой отправке в App Store.
Определите потенциальные баги:
- Пользователь добавляет товары в корзину, получает звонок, возвращается через 5 минут
- Пользователь даёт разрешение на геолокацию «При использовании», но приложению нужна геолокация для отслеживания доставки в фоне
- У пользователя Dynamic Type установлен на максимальный размер доступности
Решение
Восстановление состояния: Данные корзины могут быть потеряны, если приложение было приостановлено и завершено. Проверить: товары в корзине, актуальность цен, корректное возобновление таймеров.
Несоответствие разрешения геолокации: С разрешением «При использовании» приложение теряет доступ к геолокации в фоне. Отслеживание доставки не будет работать. Нужно запрашивать «Всегда» или объяснять необходимость.
Переполнение Dynamic Type: Большие размеры шрифта часто вызывают: обрезку текста, наложение меток, слишком маленькие кнопки, нежелательный горизонтальный скроллинг.
Советы из продакшен-опыта
Совет 1: Тестируйте на самой старой поддерживаемой версии iOS первой. Большинство крашей происходит на старых версиях, где устаревшие API могут вести себя иначе.
Совет 2: Используйте Xcode Organizer для реальных данных о крашах. После бета-тестирования через TestFlight Organizer показывает реальные отчёты о крашах от тестировщиков.
Совет 3: Тестируйте состояние «Не определено» для разрешений. iOS показывает диалог разрешения только один раз. Проверьте поведение приложения, когда разрешение никогда не запрашивалось vs когда было явно отклонено.
Ключевые выводы
- Переходы жизненного цикла iOS — частый источник багов, тестируйте прерывания и восстановление
- XCUITest — нативный фреймворк UI-автоматизации iOS
- Xcode Instruments необходим для профилирования производительности и памяти
- Тестирование разрешений должно покрывать первый запрос, отказ, отзыв и ограниченный доступ
- Отклонения App Store обычно вызваны багами, незавершёнными функциями или нарушением гайдлайнов