Как написать макротест

Библиотека Macrobenchmark позволяет тестировать более крупные сценарии использования приложения, включая его запуск и сложные манипуляции с интерфейсом, такие как прокрутка LazyColumn или запуск анимации. Если вы хотите протестировать меньшие области кода, ознакомьтесь с разделом Микротестирование. На этой странице показано, как настроить Библиотека макротестов.

Библиотека выводит результаты тестирования в консоль Android Studio и в файл JSON с более подробной информацией. Он также предоставляет файлы трассировки, которые можно загрузить и проанализировать в Android Studio.

Используйте библиотеку Macrobenchmark в среде непрерывной интеграции (CI), как описано в разделе Тестирование в непрерывной интеграции.

Вы можете использовать Macrobenchmark для создания профилей Baseline. Сначала настройте библиотеку Macrobenchmark, а затем создайте профиль Baseline Profile.

Macrobenchmark – это рекомендуемый инструмент для тестирования интерфейсов, созданных с помощью Jetpack Compose. Чтобы узнать, как писать тесты UI Automator, взаимодействующие с узлами Compose, ознакомьтесь с разделом Совместимость.

Настройка проекта

Рекомендуем использовать Macrobenchmark с последней версией Android Studio.

Настройка модуля Macrobenchmark

Для макротестов требуется модуль com.android.test, отдельный от кода приложения. Он отвечает за запуск тестов, которые оценивают приложение.

В Android Studio есть шаблон, который упрощает настройку модуля Macrobenchmark. Шаблон модуля тестирования автоматически создает в проекте модуль для измерения приложения, созданного модулем приложения, включая пример теста запуска.

Чтобы создать модуль на основе шаблона, выполните следующие действия:

  1. На панели Project (Проект) в Android Studio нажмите правой кнопкой мыши на проект или модуль и выберите New > Module (Создать > Модуль).

  2. На панели Шаблоны выберите Сравнение. Вы можете настроить целевое приложение, то есть приложение, которое будет тестироваться, а также имя пакета и модуля для нового модуля Macrobenchmark.

  3. Нажмите Готово.

Шаблон модуля тестирования.
Рисунок 1. Шаблон модуля сравнения.

Как настроить приложение

Чтобы протестировать приложение (цель Macrobenchmark), оно должно быть profileable. Это позволяет считывать подробную информацию о трассировке, не влияя на производительность. Мастер модулей автоматически добавляет тег <profileable> в файл AndroidManifest.xml приложения.

Убедитесь, что целевое приложение включает ProfilerInstaller 1.3 или более поздней версии. Это необходимо библиотеке Macrobenchmark, чтобы включить захват и сброс профиля, а также очистку кеша шейдеров.

Настройте тестируемое приложение так, чтобы оно было максимально приближено к рабочей версии. Настройте его как неотладочный и желательно с включенной минификацией, которая повышает производительность. Обычно для этого создается копия варианта выпуска, которая работает так же, но подписывается локально с помощью ключей отладки. Вы также можете использовать initWith, чтобы Gradle сделал это за вас:

Kotlin

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
    }

    create("benchmark") {
        initWith(getByName("release"))
        signingConfig = signingConfigs.getByName("debug")
    }
}

Яркий

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "keep-rules.pro"
        )
        // In real app, this would use its own release keystore
        signingConfig = signingConfigs.getByName("debug")
        baselineProfile.automaticGenerationDuringBuild = true
    }
}

Чтобы при запуске теста производительности создавался и тестировался правильный вариант приложения, как показано на рисунке 2, сделайте следующее:

  1. Выполните синхронизацию Gradle.
  2. Откройте панель Build Variants (Варианты сборки).
  3. Выберите вариант теста производительности для приложения и модуля Macrobenchmark.
Выберите контрольный вариант.
Рисунок 2. Выберите контрольный вариант.

Как настроить многомодульное приложение (необязательно)

Если в приложении несколько модулей Gradle, убедитесь, что скрипты сборки знают, какой вариант сборки компилировать. Добавьте свойство matchingFallbacks в тип сборки benchmark модулей :macrobenchmark и :app. Остальные модули Gradle могут иметь ту же конфигурацию, что и раньше.

Kotlin

create("benchmark") {
    initWith(getByName("release"))
    signingConfig = signingConfigs.getByName("debug")

    matchingFallbacks += listOf("release")
 }

Яркий

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
 }

Без этого новый тип сборки benchmark приведет к сбою сборки и появится следующее сообщение об ошибке:

> Could not resolve project :shared.
     Required by:
         project :app
      > No matching variant of project :shared was found.
      ...

При выборе вариантов сборки в проекте укажите benchmark для модулей :app и :macrobenchmark и release для всех остальных модулей в приложении, как показано на рисунке 3.

Варианты тестирования для многомодульного проекта с выбранными типами сборки для релиза и тестирования.
Рисунок 3. Варианты тестирования для многомодульного проекта с выбранными типами сборки release и benchmark.

Подробнее о том, как устранить ошибки сборки, связанные с сопоставлением вариантов…

Как настроить версии продукта (необязательно)

Если в приложении задано несколько версий продукта, настройте модуль :macrobenchmark так, чтобы он знал, какую версию продукта нужно собрать и протестировать.

В примерах на этой странице используются две версии продукта в модуле :app: demo и production. Они показаны в следующем фрагменте кода:

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
        // ...
    }
    create("production") {
        dimension = "environment"
        // ...
    }
}

Яркий

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
        // ...
    }

    production {
        dimension 'environment'
        // ...
    }
}

Если этого не сделать, может возникнуть ошибка сборки, похожая на ту, которая возникает при наличии нескольких модулей Gradle:

Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
   > Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
      > Could not resolve project :app.
        Required by:
            project :macrobenchmark
         > The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
             -   demoBenchmarkRuntimeElements
             -   productionBenchmarkRuntimeElements
           All of them match the consumer attributes:
           ...

В следующих двух разделах описаны способы настройки тестирования производительности с несколькими версиями продукта.

Используйте missingDimensionStrategy

Если указать missingDimensionStrategy в defaultConfig модуля :macrobenchmark, система сборки будет использовать группу вариантов. Укажите, какие параметры нужно использовать, если вы не нашли их в модуле. В примере ниже в качестве параметра по умолчанию используется production:

Kotlin

defaultConfig {
    missingDimensionStrategy("environment", "production")
}

Яркий

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Таким образом, модуль :macrobenchmark может создавать и тестировать только указанную версию продукта. Это полезно, если вы знаете, что только одна версия продукта имеет правильную конфигурацию для тестирования.

Определите версии продукта в модуле :macrobenchmark

Если вы хотите создать и протестировать другие версии продукта, определите их в модуле :macrobenchmark. Укажите его так же, как в модуле :app, но присвойте productFlavors только dimension. Другие настройки не требуются.

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
    }
    create("production") {
        dimension = "environment"
    }
}

Яркий

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
    }

    production {
        dimension 'environment'
    }
}

После определения и синхронизации проекта выберите нужный вариант сборки на панели Build Variants (Варианты сборки), как показано на рисунке 4.

Контрольные варианты для проекта с версиями продукта, в котором выбраны productionBenchmark и выпуск.
Рисунок 4. Контрольные варианты для проекта с версиями продукта, в которых выбраны productionBenchmark и release.

Подробнее о том, как устранить ошибки сборки, связанные с сопоставлением вариантов…

Создайте класс Macrobenchmark

Тестирование производительности выполняется с помощью правила MacrobenchmarkRule JUnit4 API в библиотеке Macrobenchmark. Он содержит метод measureRepeated, который позволяет задавать различные условия для запуска и тестирования целевого приложения.

Вам нужно указать как минимум packageName целевого приложения, что вы хотите metrics и сколько iterations должен выполняться тест.

Kotlin

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

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = TARGET_PACKAGE,
        metrics = listOf(StartupTimingMetric()),
        iterations = DEFAULT_ITERATIONS,
    ) {
        // starts default launch activity
        uiAutomator { startApp(TARGET_PACKAGE) }
    }
}

Подробнее о настройке контрольных показателей…

Тестирование взаимодействий с интерфейсом Compose

В предыдущем примере мы измеряли время запуска приложения, но часто требуется измерить производительность интерфейса, например пропуск кадров (помехи) при прокрутке.

Чтобы протестировать приложение Jetpack Compose, например измерить FrameTimingMetric при прокрутке LazyColumn, вы можете использовать UI Automator для прямого взаимодействия с узлами Compose, как показано в следующем фрагменте кода.

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

    @Test
    fun scrollLazyColumn() = benchmarkRule.measureRepeated(
        packageName = "com.example.compose.app",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.WARM,
        setupBlock = { pressHome() }
    ) {
        startActivityAndWait()

        // Find the Compose node using the testTag defined in your app
        val lazyColumn = device.findObject(By.res("my_lazy_column"))

        // Simulate a scroll gesture to measure FrameTimingMetric
        lazyColumn.setGestureMargin(device.displayWidth / 5)
        lazyColumn.fling(Direction.DOWN)
    }
}

Как запустить тест

Запустите тест в Android Studio, чтобы оценить производительность приложения на устройстве. Вы можете запустить тесты производительности так же, как и любые другие тесты @Test, используя действие на полях рядом с тестовым классом или методом, как показано на рисунке 5.

Запустите Macrobenchmark, нажав на значок рядом с тестовым классом.
Рисунок 5. Запустите Macrobenchmark, нажав на значок на полях рядом с тестовым классом.

Вы также можете запустить все тесты в модуле Gradle из командной строки, выполнив команду connectedCheck:

./gradlew :macrobenchmark:connectedCheck

Чтобы запустить один тест, выполните следующую команду:

./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup

Подробнее о том, как запускать и отслеживать тесты производительности в непрерывной интеграции…

Результат сравнения

После успешного запуска теста показатели отображаются непосредственно в Android Studio и выводятся для использования CI в файле JSON. Каждая итерация измерения фиксирует отдельную трассировку системы. Чтобы открыть результаты трассировки, нажмите на ссылки на панели Test Results (Результаты тестирования), как показано на рисунке 6.

Результаты запуска Macrobenchmark.
Рисунок 6. Результаты запуска Macrobenchmark.

Когда трассировка загрузится, Android Studio предложит вам выбрать процесс для анализа. В списке будет выбран процесс целевого приложения, как показано на рисунке 7.

Выбор процесса отслеживания в Студии.
Рисунок 7. Выбор процесса трассировки в Android Studio.

После загрузки файла трассировки Studio показывает результаты в профилировщике ЦП.

Трассировка Studio.
Рисунок 8. Studio trace.

Отчеты JSON и трассировки профилирования также автоматически копируются с устройства на хост. Они записываются на хост-компьютере в следующую папку:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

Как получить доступ к файлам трассировки вручную

Если вы хотите использовать инструмент Perfetto для анализа файла трассировки, вам нужно выполнить дополнительные действия. Perfetto позволяет проверять все процессы, происходящие на устройстве во время трассировки, а профилировщик ЦП в Android Studio – только один процесс.

Если вы запускаете тесты из Android Studio или командной строки Gradle, файлы трассировки автоматически копируются с устройства на хост. Они записываются на хост-машине в следующем месте:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace

Когда файл трассировки появится в хост-системе, вы сможете открыть его в Android Studio, выбрав в меню File (Файл) > Open (Открыть). Это показывает представление инструмента профилировщика, показанное в предыдущем разделе.

Ошибки конфигурации

Если приложение настроено неправильно (доступно для отладки или недоступно для профилирования), Macrobenchmark возвращает ошибку, а не сообщает о неверном или неполном измерении. Вы можете подавить эти ошибки с помощью аргумента androidx.benchmark.suppressErrors.

Macrobenchmark также возвращает ошибки при попытке измерения на эмуляторе или на устройстве с низким зарядом батареи, что может поставить под угрозу доступность ядра и тактовую частоту.

Как настроить контрольные показатели

Функция measureRepeated принимает различные параметры, которые влияют на то, какие показатели собирает библиотека, как запускается и компилируется приложение и сколько итераций выполняет тест.

Сбор показателей

Показатели – это основной тип информации, извлекаемой из контрольных показателей. Доступны следующие показатели:

Дополнительную информацию о показателях можно найти в статье Как собирать показатели Macrobenchmark.

Как улучшить данные трассировки с помощью специальных событий

Вы можете добавить в приложение специальные события трассировки, которые будут отображаться в отчете и помогут выявить проблемы, характерные для вашего приложения. Подробнее о том, как создавать специальные события трассировки…

CompilationMode

В макротестах можно указать CompilationMode, чтобы определить, какая часть приложения должна быть предварительно скомпилирована из байт-кода DEX (формат байт-кода в APK) в машинный код (аналогично предварительно скомпилированному C++).

По умолчанию макротесты выполняются с помощью CompilationMode.DEFAULT, который устанавливает профиль базовой конфигурации (если он доступен) на устройствах с Android 7 (уровень API 24) и более поздними версиями. Если вы используете Android 6 (уровень API 23) или более ранней версии, режим компиляции полностью компилирует APK-файл по умолчанию.

Вы можете установить профиль Baseline, если целевое приложение содержит и профиль Baseline, и библиотеку ProfileInstaller.

На устройствах с Android 7 и более поздними версиями ОС можно настроить CompilationMode, чтобы изменить объем предварительной компиляции на устройстве и имитировать разные уровни предварительной компиляции (AOT) или JIT-кэширования. См. CompilationMode.Full, CompilationMode.Partial, CompilationMode.None и CompilationMode.Ignore.

Эта функция основана на командах компиляции ART. Перед запуском каждого теста данные профиля очищаются, чтобы избежать помех.

StartupMode

Чтобы запустить действие, можно передать предопределенный режим запуска: COLD, WARM или HOT. Этот параметр определяет, как запускается действие и в каком состоянии находится процесс в начале теста.

Подробнее о типах запуска…

Образцы

Пример проекта доступен в примере Macrobenchmark репозитория на GitHub.

Отправить отзыв

Сообщить о проблемах или отправить запрос на добавление функций для Jetpack Macrobenchmark можно в общедоступной системе отслеживания ошибок.