App über MacroBenchmark steuern

Im Gegensatz zu den meisten Android-UI-Tests werden MacroBenchmark-Tests in einem separaten Prozess ausgeführt direkt in der App. Dies ist erforderlich, um z. B. die App-Prozess und Kompilierung vom DEX-Bytecode in Maschinencode.

Sie können den Status Ihrer App mithilfe der UIAutomator-Bibliothek oder einer anderen Mechanismen, mit denen die Ziel-App über den Testprozess gesteuert werden kann. Sie können Espresso oder ActivityScenario nicht verwenden für MacroBenchmark, da er erwartet, dass er in einem gemeinsamen Prozess mit der App ausgeführt wird.

Im folgenden Beispiel wird ein RecyclerView anhand seiner Ressourcen-ID und mehrfach nach unten scrollt:

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;
        }
    );
}

Für die Benchmark muss auf der Benutzeroberfläche nicht gescrollt werden. Stattdessen wird eine z. B. Animation. Außerdem muss UI Automator nicht verwendet werden. spezifisch sind. Sie erfasst Leistungsmesswerte, die vom Ansichtssystem generiert wurden, einschließlich Frames, die mit Jetpack Compose erstellt wurden.

Manchmal möchten Sie Teile Ihrer App vergleichen, die nicht direkt von außen zugänglich zu machen. Das kann zum Beispiel der Zugriff auf innere Aktivitäten sein die mit exported=false markiert sind, zu einem Fragment navigieren oder einen Teil der Benutzeroberfläche entfernt. Die Benchmarks müssen diese manuell aufrufen, der App wie Nutzende.

Ändern Sie den Code in setupBlock{} so, dass er den Parameter Effekts, z. B. Tippen auf Schaltflächen oder Wischen. Dein measureBlock{} enthält nur die UI-Manipulation, die Sie für das Benchmarking durchführen möchten:

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 -> {
            // ...
        }
    );
}