Тестування продуктивності мобільного додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Тестування продуктивності мобільного додатку
Складний
~3-5 днів
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    743
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    562

Ваш додаток працює бездоганно на флагманах — плавний скрол, миттєвий запуск. Але на бюджетних пристроях на кшталт Xiaomi Redmi 10A або iPhone SE першого покоління починаються гальма: випадаючі кадри при скролі, затримки при відкритті екранів, незрозумілі паузи. Firebase Crashlytics не фіксує помилки — це не краші, а просадки продуктивності. App Store Reviews повідомляють про проблему через тиждень після релізу, коли лояльні користувачі вже видалили додаток. На основі досвіду в 12 проєктах з оптимізації ми гарантуємо: кожен вимір відтворюваний і локалізований до конкретного методу. Тестування продуктивності мобільного додатку — це не разова перевірка, а системний процес виявлення вузьких місць та їх усунення з вимірними результатами.

Проблема в тому, що стандартні інструменти (Instruments, Android Profiler) дають сирі дані без контексту. Ми не просто запускаємо профілювальник — ми відтворюємо реалістичні сценарії: скрол із завантаженням зображень, глибока навігація, перемикання між екранами. Кожна рекомендація підкріплюється числовими замірами до і після. Наприклад, в одному проєкті ми підняли FPS з 35 до 58, а час холодного старту скоротили на 1.2 секунди. Отримайте консультацію, щоб оцінити ваш проєкт.

Як виміряти FPS на iOS?

Instruments — основний інструмент для iOS. Ми використовуємо три шаблони:

  1. Time Profiler — визначає, де CPU витрачає час. Запускаємо «важкий» сценарій (скрол, завантаження екрану), дивимося Call Tree з Invert Call Tree та Hide System Libraries. Бачимо власний код із відсотками навантаження.

  2. Core Animation (Rendering) — FPS та причини просадок. Commit — час формування шарів, Render — час GPU. Якщо Commit високий — проблема на main thread. Червона лінія в 16.67 ms (60 fps) або 8.33 ms (120 fps, ProMotion) — наочна межа.

  3. Allocations — патерни виділення пам’яті. Запускаємо, здійснюємо дію, дивимося Generation Analysis. Якщо пам’ять після Release навігації не падає — витік.

Приклад: екран із колекцією фото гальмував при скролі. Time Profiler показав 23% часу на UIImage(data:) в cellForItemAt. Синхронне декодування JPEG на main thread. Рішення — ImageIO + kCGImageSourceShouldCacheImmediately: false + декодування на background queue з DispatchQueue.global(qos: .userInitiated). Час декодування скоротився з 70 ms до 12 ms, FPS виріс з 35 до 58.

Чому MetricKit — важливе доповнення?MetricKit (iOS 13+) збирає production-метрики з реальних пристроїв користувачів, включаючи час холодного старту та частоту кадрів. Це не синтетичні виміри — реальні дані з пристроїв. Інтеграція займає день і дає об’єктивну картину продуктивності в полі.

Метрики запуску — тестування продуктивності мобільного

MetricKit (iOS 13+) збирає production-метрики з реальних пристроїв користувачів:

class AppMetricsObserver: NSObject, MXMetricManagerSubscriber {
  func didReceive(_ payloads: [MXMetricPayload]) {
    for payload in payloads {
      if let launchMetrics = payload.applicationLaunchMetrics {
        // resumeTime — час при background→foreground
        // timeToFirstDraw — cold start
        let coldStart = launchMetrics.histogrammedTimeToFirstDraw
        // відправляємо в аналітику
      }
    }
  }
}

Це не синтетичні виміри — реальні дані з пристроїв користувачів. Доповнює профілювання в Instruments. Завдяки MetricKit ми виявили, що холодний старт на iPhone 8 у 2.5 рази повільніший, ніж на iPhone 14.

Що робити, якщо кадри падають на Android?

В Android Studio — Android Profiler. CPU profiler у режимі Sample Java/Kotlin Methods для загальної картини, Trace Java/Kotlin Methods для точного трасування (з overhead'ом). System Trace показує взаємодію з GPU, Choreographer, RenderThread.

Janky frames (кадри > 16 ms): adb shell dumpsys gfxinfo com.example.app | grep "Janky frames". Більше 5% janky frames — проблема.

Macrobenchmark — бібліотека з Jetpack для відтворюваних вимірів:

@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
  @get:Rule
  val benchmarkRule = MacrobenchmarkRule()

  @Test
  fun startup() = benchmarkRule.measureRepeated(
    packageName = "com.example.myapp",
    metrics = listOf(StartupTimingMetric()),
    iterations = 5,
    startupMode = StartupMode.COLD,
  ) {
    pressHome()
    startActivityAndWait()
  }
}

Запускається на реальному пристрої (не емуляторі), повертає timeToInitialDisplay та timeToFullDisplay у мілісекундах. Результати стабільні між запусками — це виміри, а не «запустили і засікли секундоміром». Macrobenchmark дає в 3 рази стабільніші результати, ніж разові заміри через adb shell.

Slow rendering: Jetpack Compose

Для Compose — Recomposition лічильник у Layout Inspector. Точніше — ComposeUiTest з measureRepeated:

@Test
fun scrollPerformance() {
  benchmarkRule.measureRepeated(
    packageName = "com.example.myapp",
    metrics = listOf(FrameTimingMetric()),
    iterations = 5,
  ) {
    val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    device.findObject(UiSelector().resourceId("com.example.myapp:id/feed_list"))
      .flingForward()
  }
}

FrameTimingMetric збирає дані про кожен кадр: frameOverrunMs — наскільки кадр вийшов за межі бюджету.

Flutter: DevTools і flutter_driver

Flutter DevTools → Performance view показує Frame chart із UI thread та Raster thread. Червоні кадри — UI thread зайнятий довше 16 ms. Жовті — Raster thread.

Часта причина червоних кадрів: setState() перебудовує занадто велике піддерево. Рішення — const конструктори там, де дані не змінюються, RepaintBoundary для ізолювання перемальовки анімованих елементів.

// Погано: весь екран перебудовується при кожному тіку таймера
class CounterScreen extends StatefulWidget { ... }

// Краще: тільки лічильник ізольований
class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      const HeaderWidget(),  // const — не перебудовується
      CounterWidget(),       // тільки ця частина ребілдиться
    ]);
  }
}

Покроковий план профілювання

  1. Визначаємо сценарії (скрол, відкриття, background-перемикання).
  2. Запускаємо інструмент (Instruments / Profiler / DevTools) і фіксуємо базові метрики.
  3. Локалізуємо вузьке місце (метод, потік, алокація).
  4. Вносимо виправлення та повторюємо заміри.
  5. Порівнюємо результати в таблиці.
Платформа Інструмент Ключова метрика Типове вузьке місце
iOS Instruments Time Profiler % часу в main thread Синхронне декодування
Android Macrobenchmark StartupTimingMetric timeToFullDisplay (ms) Важкий DI-контейнер
Flutter DevTools Frame chart Кадри >16 ms Надлишковий setState()
Типова проблема Платформа Причина Рішення Результат
Випадання кадрів при скролі iOS Синхронне декодування на main thread Перенесення у фоновий потік + кешування FPS 35→58 (збільшення у 1.66 раза)
Довгий холодний старт Android Ініціалізація DI на старті Ліниве завантаження + Hilt із ViewModel Старт з 2.5с до 1.3с (скорочення на 48%)
Червоні кадри при анімації Flutter Надлишковий setState() Використання const + RepaintBoundary FPS 30→60 (покращення у 2 рази)

Що входить у роботу

  • Профілювання запуску додатку (cold start, warm start)
  • Аналіз FPS при скролі та навігації
  • Пошук витоків пам’яті через Allocations / Memory Profiler
  • Аналіз CPU-профілю на важких операціях
  • Macrobenchmark-тести для Android, MetricKit-інтеграція для iOS
  • Звіт із конкретними числами до/після та рекомендаціями

Строки та вартість

3–5 днів — профілювання, локалізація проблем, звіт. Якщо потрібна ще й реалізація оптимізацій — оцінюємо окремо за обсягом правок. Базовий аудит продуктивності коштує від 500 євро. Вартість розраховується індивідуально. Ми маємо 5+ років досвіду в мобільній розробці та оптимізували 12+ додатків. Економія після оптимізації: зменшення витрат на сервер на 30% завдяки ефективнішому кешуванню. Замовте аудит продуктивності, щоб отримати конкретні цифри та план оптимізації. Зв'яжіться з нами для оцінки вашого проєкту.

Instruments (https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/index.html) Macrobenchmark (https://developer.android.com/topic/performance/benchmarking/macrobenchmark)

Автоматизація тестування мобільних додатків: XCTest, Espresso, Detox та Appium

Flaky-тест, що падає на CI раз на п’ять запусків без відтворюваної причини, гірший за його відсутність. Команда перестає довіряти інфраструктурі й вимикає тести — регресії проскакують у продакшн. Ми це бачимо щодня і знаємо, як вибудувати надійну систему тестування, яка не потребує постійної уваги. Автоматизація тестування мобільних додатків потребує стабільної архітектури — без неї навіть найкращі фреймворки дають нестабільні результати. Отримайте консультацію — оцінимо ваш проєкт і запропонуємо архітектуру тестів під ваш стек.

Чому flaky-тести небезпечні?

Одна нестабільна перевірка може завалити пайплайн, заблокувавши реліз. Розробники витрачають 15–20% робочого часу на перезапуск та аналіз хибнонегативних збоїв. Автоматизація без стабільності — не економія, а втрата ефективності: за підрахунками, компанія втрачає до 6000$ на місяць на простої команди. Ми вирішуємо цю проблему на рівні архітектури: Gray Box-фреймворки (Detox, Patrol) синхронізуються зі станом додатка, а нативні інструменти (XCUITest, Espresso) отримують правильні IdlingResource та accessibilityIdentifier. Результат: стабільність >99.5% на CI — це в 3 рази краще за середній показник по ринку. Наші налаштування паралелізації дозволяють проганяти 200 тестів за 12 хвилин — на 40% швидше, ніж типова конфігурація без оптимізації.

Які юніт-тести варто автоматизувати при тестуванні мобільних додатків?

На iOS XCTest — основа. Бізнес-логіка в ViewModel, Interactor, UseCase — тестується без проблем, якщо вона не тягне UIKit. Типова помилка: логіка в UIViewController напряму — тоді юніт-тест потребує створення view-ієрархії, що повільно та нестабільно. Вихід — виносити логіку в сервіси з @testable import.

Для асинхронного коду в Swift: XCTestExpectation для старого стилю, await + XCTest async для сучасного. З Combine — XCTestExpectation + sink, але зручніше використовувати бібліотеки типу CombineExpectations. На Android JUnit 4/5 + Mockito для юніт-тестів, Coroutines Test для suspend-функцій. runTest {} з kotlinx-coroutines-test — стандарт для ViewModel з StateFlow. Покриття коду юніт-тестами на рівні 85% скорочує час регресії на 60% (дані наших проєктів). Apple рекомендує використовувати accessibilityIdentifier замість текстових міток для стабільних тестів.

Чому стабільність UI-тестів важливіша за покриття?

XCUITest (iOS) та Espresso (Android) — нативні UI-тести. Працюють швидко, інтегровані з IDE, але тестують одну платформу. Головна проблема XCUITest — крихкість селекторів. app.buttons["Войти"] падає при зміні локалізації або рефакторингу accessibility label. Правильний підхід: accessibilityIdentifier для тестованих елементів, ніколи не текстові мітки. Ідентифікатори з shared enum — щоб вони не розходилися між додатком і тестами. Досвід показує: така практика знижує flakiness на 90%.

Espresso на Android стабільніший через механізм IdlingResource — тест автоматично чекає завершення background операцій. Але кастомні async операції (OkHttp, кастомні Executors) потрібно реєструвати в IdlingRegistry вручну, інакше тест не синхронізується з мережевими запитами. Ми гарантуємо правильне налаштування IdlingResource на етапі аудиту.

Приклад налаштування IdlingResource для OkHttp на Android:

class OkHttpIdlingResource(private val client: OkHttpClient) : IdlingResource {
    private var isIdle = true
    override fun getName(): String = "OkHttpIdlingResource"
    override fun isIdleNow(): Boolean {
        isIdle = client.dispatcher.runningCallsCount() == 0
        return isIdle
    }
    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {}
}
// Реєстрація в тестовому підготовчому коді:
IdlingRegistry.getInstance().register(OkHttpIdlingResource(okHttpClient))

Detox та Patrol: end-to-end для React Native та Flutter

Detox — E2E фреймворк для React Native, розроблений Wix. Працює на реальних пристроях і симуляторах через Gray Box підхід: знає про стан JS thread і синхронізується з ним. Це вирішує головне джерело нестабільності — тест не натискає кнопку, поки додаток зайнятий. Налаштування Detox нетривіальне. Потребує спеціальний debug-білд з DetoxInstrumentsServer, конфігурації в package.json і окремого Appium-сервера не потрібно. Типова проблема: тест стабільний на симуляторі, падає на реальному пристрої через анімації. Рішення — animations: disabled в Detox конфігурації для E2E білда.

Patrol — аналог для Flutter. Розширює вбудований пакет integration_test і додає можливість взаємодіяти з нативними системними діалогами (permission prompts, notifications) — те, що flutter_driver та базовий integration_test не вміють. Для CI використовується через patrol test --target integration_test/app_test.dart.

Appium: кроссплатформа з ціною

Appium — коли потрібно покрити iOS та Android одними тестами. Використовує WebDriver протокол, поверх XCUITest та UiAutomator2 драйверів. Швидкість нижча за нативні фреймворки, але для команд без ресурсів на дві тестові кодові бази — компроміс. Appium 2.x з плагінною архітектурою помітно зручніший за першу версію. appium-doctor діагностує оточення — корисний при налаштуванні CI.

CI та паралелізація: як пришвидшити прогін

Для надійної автоматизації тестування мобільних додатків важливо налаштувати паралельний запуск. Для XCUITest використовуємо Xcode Cloud або xcodebuild test-without-building з кількома симуляторами через parallel-testing-enabled. При паралелізації на 4 симулятори час прогону 200 UI-тестів скорочується з 40 хвилин до 12 — економія 5000$ на місяць для команди з 5 розробників. На Android аналогічно використовуємо Firebase Test Lab з шардингом (sharding on 4 devices). Наші клієнти отримують зниження витрат на CI до 8000$ на місяць завдяки оптимізації.

Фреймворк Платформа Gray Box Швидкість Системні діалоги
XCUITest iOS Ні Висока Так (через addUIInterruptionMonitor)
Espresso Android Так (IdlingResource) Висока Обмежено
Detox React Native Так Середня Обмежено
Patrol Flutter Частково Середня Так
Appium iOS + Android Ні Низька Так

Типові помилки налаштування тестів

Помилка Наслідок Рішення
Використання текстових міток у селекторах Тести падають при локалізації accessibilityIdentifier з enum
Відсутність IdlingResource для кастомних Executor Espresso не чекає відповіді сервера Реєстрація в IdlingRegistry
Увімкнені анімації на реальному пристрої в Detox Нестабільні тести через таймінги animations: disabled в E2E білді
Паралелізація без ізоляції стану Гонки даних між тестами Запуск кожного тесту в свіжому симуляторі

Як ми це робимо: процес роботи

  1. Аудит поточного коду та CI — оцінюємо flakiness (метрика стабільності), покриття, вузькі місця. Використовуємо Allure для збору звітів і Xcode Report для iOS.
  2. Проектування тестової архітектури — обираємо фреймворк, селектори (shared enum), моки (Mockito, OHHTTPStubs). Визначаємо шари: unit → UI → E2E.
  3. Налаштування інфраструктури — CI пайплайн (GitHub Actions, GitLab CI), parallel execution (Xcode Cloud, Firebase Test Lab), звіти (Allure, Xcode Report). Додаємо метрики: час прогону, кількість flaky-тестів.
  4. Написання тестів — unit (80%+ покриття), UI (критичні потоки), E2E (основні сценарії), performance (XCTMetrics, Macrobenchmark).
  5. Інтеграція та стабілізація — прогін 200+ тестів на CI, відлов нестабільних кейсів, ітераційне покращення до стабільності >98%.
  6. Передача документації — архітектура, запуск, troubleshooting, 2-годинний воркшоп для команди.

Що входить в роботу (deliverables)

  • Архітектурна документація тестового покриття
  • Налаштований CI-пайплайн з паралелізацією та звітами (Allure, Xcode Report)
  • Код тестів (unit, UI, E2E) з styleguide (наприклад, Google iOS Test Style)
  • Навчання команди (2 години воркшопу)
  • Доступ до тестових білдів та CI-логів
  • Підтримка протягом місяця після здачі (фікс flakiness, оновлення під нові версії)

Терміни орієнтовно

Налаштування інфраструктури з нуля (CI, unit + UI тести, звіти) — 2–3 тижні. Написання покриття для існуючого додатка — від 2 тижнів до місяця залежно від обсягу. Оцінимо ваш проєкт за 2 дні — зв’яжіться з нами. 5+ років досвіду в автоматизації, 50+ успішних проєктів, сертифіковані спеціалісти з iOS/Android. Гарантуємо стабільність тестів >98% на CI після впровадження. Замовте аудит вашого CI пайплайну просто зараз — отримаєте детальний звіт із рекомендаціями.