Contrairement à la plupart des tests de l'interface utilisateur Android, les tests Macrobenchmark s'exécutent dans un processus distinct de l'appli elle-même. Cela est nécessaire pour permettre, entre autres, d'arrêter le processus de l'application et de compiler du bytecode DEX en code machine.
Vous pouvez contrôler l'état de votre application à l'aide de la bibliothèque UIAutomator ou d'autres mécanismes pouvant contrôler l'application cible à partir du processus de test.
Vous ne pouvez pas utiliser Espresso ni ActivityScenario
pour Macrobenchmark, car ils doivent s'exécuter dans un processus partagé avec l'application.
L'exemple suivant trouve une RecyclerView
à l'aide de son ID de ressource et fait défiler plusieurs fois vers le bas :
Kotlin
@Test fun scrollList() { benchmarkRule.measureRepeated( // ... setupBlock = { // Before starting to measure, navigate to the UI to be measured val intent = Intent("$packageName.RECYCLER_VIEW_ACTIVITY") startActivityAndWait(intent) } ) { val recycler = device.findObject(By.res(packageName, "recycler")) // Set gesture margin to avoid triggering gesture navigation // with input events from automation. recycler.setGestureMargin(device.displayWidth / 5) // Scroll down several times repeat(3) { recycler.fling(Direction.DOWN) } } }
Java
@Test public void scrollList() { benchmarkRule.measureRepeated( // ... /* setupBlock */ scope -> { // Before measuring, navigate to the UI to be measured. val intent = Intent("$packageName.RECYCLER_VIEW_ACTIVITY") scope.startActivityAndWait(); return Unit.INSTANCE; }, /* measureBlock */ scope -> { UiDevice device = scope.getDevice(); UiObject2 recycler = device.findObject(By.res(scope.getPackageName(), "recycler")); // Set gesture margin to avoid triggering gesture navigation // with input events from automation. recycler.setGestureMargin(device.getDisplayWidth() / 5); // Fling the recycler several times. for (int i = 0; i < 3; i++) { recycler.fling(Direction.DOWN); } return Unit.INSTANCE; } ); }
Votre benchmark n'a pas besoin de faire défiler l'interface utilisateur. À la place, il peut par exemple exécuter une animation. Il n'a pas non plus besoin d'utiliser UIAutomator en particulier. Il collecte des métriques de performances tant que les frames sont produits par le système de vues, qui comprend les frames produits par Jetpack Compose.
Accéder aux parties internes de l'application
Vous pouvez parfois comparer des parties de votre application qui ne sont pas directement accessibles de l'extérieur. Il peut s'agir, par exemple, d'accéder à des activités internes marquées de exported=false
, d'accéder à un Fragment
ou de balayer une partie de votre interface utilisateur pour la faire disparaître. Les benchmarks doivent accéder manuellement à ces parties de l'application, comme le ferait un utilisateur.
Pour naviguer manuellement, modifiez le code dans setupBlock{}
pour contenir l'effet souhaité, par exemple un appui sur un bouton ou un balayage. Votre measureBlock{}
ne contient que la manipulation de l'interface utilisateur que vous souhaitez comparer :
Kotlin
@Test fun nonExportedActivityScrollList() { benchmarkRule.measureRepeated( // ... setupBlock = setupBenchmark() ) { // ... } } private fun setupBenchmark(): MacrobenchmarkScope.() -> Unit = { // Before starting to measure, navigate to the UI to be measured startActivityAndWait() // click a button to launch the target activity. // While we use button text here to find the button, you could also use // accessibility info or resourceId. val selector = By.text("RecyclerView") if (!device.wait(Until.hasObject(selector), 5_500)) { fail("Could not find resource in time") } val launchRecyclerActivity = device.findObject(selector) launchRecyclerActivity.click() // wait until the activity is shown device.wait( Until.hasObject(By.clazz("$packageName.NonExportedRecyclerActivity")), TimeUnit.SECONDS.toMillis(10) ) }
Java
@Test public void scrollList() { benchmarkRule.measureRepeated( // ... /* setupBlock */ scope -> { // Before measuring, navigate to the default activity. scope.startActivityAndWait(); // Click a button to launch the target activity. // While you use resourceId here to find the button, you can also // use accessibility info or button text content. UiObject2 launchRecyclerActivity = scope.getDevice().findObject( By.res(packageName, "launchRecyclerActivity") ) launchRecyclerActivity.click(); // Wait until activity is shown. scope.getDevice().wait( Until.hasObject(By.clazz("$packageName.NonExportedRecyclerActivity")), 10000L ) return Unit.INSTANCE; }, /* measureBlock */ scope -> { // ... } ); }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Écrire un macrobenchmark
- Capturer les métriques Macrobenchmark
- Microbenchmark