mobilenetworkingregression

Тестирование на плохую сеть — 8 сценариев и инструменты

Большинство мобильных приложений ломаются не на «нет интернета», а на «есть, но плохой». QA-команды чаще всего проверяют только два состояния — Wi-Fi есть и Airplane mode. Реальные пользователи живут между ними: 4G в метро с провалами, captive portal в кафе, медленный гостевой Wi-Fi в отеле, мобильная вышка в дальнем углу торгового центра.

Этот гайд — 8 сценариев, без которых regression-чеклист мобильного приложения нельзя считать полным. Для каждого: что именно ломается, какими инструментами воспроизвести, и какой минимальный приёмочный тест.

1. Тротлинг скорости (2G / 3G / слабый Wi-Fi)

Что ломается: таймауты на стороне клиента стреляют раньше, чем сервер успевает ответить → retry-логика выстреливает дубликатами запросов; спиннеры зависают без cancel-кнопки; SDK инициализации (Adjust, Firebase, AppLovin) держат стартовый бутстрап заложником медленного fetch’а конфига.

Инструменты: Network Link Conditioner (iOS: Settings → Developer → Network Link Conditioner; macOS: устанавливается через Additional Tools for Xcode), Proxyman (Tools → Network Conditions → Throttling), Charles (Proxy → Throttle Settings), Android Studio Network Profiler.

Минимальный тест: профиль «3G» (~780 kbps down / 330 kbps up, 100ms latency) — golden path (логин → главный экран → ключевое действие → выход) проходит за ≤ 30 секунд без зависаний. Все «загрузка…» имеют либо прогресс, либо cancel-кнопку.

2. Packet loss и jitter

Что ломается: WebSocket-соединения теряют ack-и и шлют дубликаты; чанковые загрузки и uploads ломаются на середине; gRPC streaming не пере-инициализируется; чаты показывают сообщения дважды.

Публичный Wi-Fi в кафе, аэропорту или самолёте легко даёт 1–5% потерь. Atc (Augmented Traffic Control от Facebook) и tc qdisc netem на Linux gateway эмулируют это точно. Network Link Conditioner имеет профиль «100% Loss» для крайнего случая.

Минимальный тест: 3% потерь на профиле «3G» — все retry-механизмы (SDK события, аналитика) идемпотентны и не создают дубли на бэкенде. Проверяй именно на бэкенде, не в логах клиента.

3. Latency spikes (5–30 секунд)

Что ломается: пользователь дабл-тапает на кнопку → дубликат запроса (IAP — двойная покупка, like — два лайка); race conditions между запросами в полёте; cache TTL истекает между запросом и ответом и UI рендерит несогласованное состояние.

Инструмент: Proxyman → Breakpoints на конкретный URL, задержать ответ на 10–20 секунд вручную и посмотреть, что происходит в UI. Charles умеет аналогично.

Минимальный тест: запросы покупки и важных действий блокируют UI кнопку или показывают loading на самой кнопке. Двойной тап через 10 секунд после первого — не триггерит второй запрос. Гарантируйте идемпотентность через Idempotency-Key header на сервере.

4. Captive portals (отели, аэропорты, кафе)

Что ломается: DNS отвечает, TCP открывается, но HTTP 200 даёт login-страницу провайдера, а не ваш контент. SDK на старте получают мусорный JSON и либо крашатся при парсинге, либо зависают в ретрае на 60 секунд. iOS auto-opens WebView для captive portal — это конфликтует с deep-link’ами.

Инструмент: локально — поднять nginx на машине, направить через /etc/hosts твой API-домен на этот nginx, который отдаёт HTTP 200 с HTML captive portal. Реальный тест — сходить с тестовым девайсом в Starbucks или Marriott.

Минимальный тест: открыть приложение в сети с captive portal до прохождения авторизации — SDK init не зависает > 5 секунд, есть fallback на cached config или явный error UI, не белый экран.

5. Wi-Fi → Cellular handoff во время запроса

Что ломается: in-flight HTTP requests прерываются на середине → клиент шлёт retry → IAP получает double-charge; uploaded видео доходит наполовину и сервер записывает повреждённый файл; WebSocket дропается без reconnect-логики.

Инструмент: руками — открыть приложение на Wi-Fi, запустить критичную операцию (IAP / upload / auth), физически отключить Wi-Fi на роутере или переключить устройство → пойдёт в LTE. На Android альтернатива — toggle Airplane mode на 2 секунды.

Минимальный тест: IAP во время handoff’а либо успешно завершается (через retry с idempotency), либо явно сообщает пользователю «купи заново». Никогда не списывает деньги дважды. Adjust SDK правильно персистит queue в файл — проверь, что свой аналитический код делает то же.

6. DNS-сбои

Что ломается: первая загрузка зависает на 60–90 секунд (системный DNS timeout), нет fallback на cached IP, нет clean error-state в UI. На корпоративных сетях часто DNS-фильтрация отбивает не-whitelist домены. У некоторых провайдеров DNS hijack — на NXDOMAIN отдают search-страницу.

Инструмент: Proxyman → DNS Spoofing, можно вернуть 127.0.0.1 или просто rejected. На macOS — /etc/resolver/<domain> с невалидным IP. Или прописать в роутере DNS 192.0.2.1 (TEST-NET-1).

Минимальный тест: с заблокированным DNS приложение показывает понятный error в ≤ 10 секунд (не 60), не крашится. Если есть offline-режим — переходит в него автоматически.

7. IPv6-only сети

Apple требует IPv6 readiness ещё с 2016 года при App Store review. T-Mobile USA уже работает только в IPv6. Дальше будет только хуже для IPv4-only кода.

Что ломается: hardcoded IPv4 в коде, конфликты 127.0.0.1 vs ::1, NAT64/DNS64 преобразования в синтетические IPv6, библиотеки сторонних SDK с устаревшим getaddrinfo.

Инструмент: macOS → System Settings → Sharing → Internet Sharing с опцией IPv6-only, либо Apple Configurator с custom Wi-Fi profile.

Минимальный тест: приложение в IPv6-only Wi-Fi — все хосты SDK (analytics, ads, backend, push) резолвятся и работают. Особое внимание — third-party SDK, известные баги были у старых версий Facebook SDK и InMobi.

8. TLS / Certificate edge-cases

Что ломается: SSL pinning блокирует приложение наглухо при ротации серверного сертификата (Adjust, AppLovin, Firebase пиннят свои CDN — если пин истёк в билде, фиксят только через release); системное время пользователя «вперёд на год» → certificate validity check fails → cryptic crash; MITM сценарий через корпоративный прокси.

Инструмент: вручную — установи системное время девайса на год вперёд, запусти приложение. Proxyman в MITM-режиме без установленного сертификата на устройстве — посмотри, какая ошибка вылезает в UI.

Минимальный тест: с неверным системным временем приложение либо работает (если SSL-чек толерантный), либо даёт понятный «проверь время на устройстве» error. Не crash.

Regression checklist на каждый релиз

  • Golden path на «3G» профиле ≤ 30 секунд
  • IAP во время Wi-Fi → cellular handoff = ровно одно списание
  • Captive portal не блокирует SDK init > 5 секунд
  • DNS-сбой = error за ≤ 10 секунд, не 60
  • Системное время +1 год = понятная ошибка, не crash
  • Latency 10 секунд + двойной тап на CTA = один запрос
  • IPv6-only сеть = все SDK работают
  • 3% packet loss = аналитические события идемпотентны на бэкенде

Итог

Проверка «нет интернета / есть интернет» — это покрытие двух точек из спектра. Реальные пользователи живут в промежутке. Эти 8 сценариев в regression-чеклисте поднимают production-устойчивость на порядок при минимальной добавочной стоимости — большинство инструментов уже есть бесплатно в iOS, macOS и Android Studio.