대부분의 Android UI 테스트와 달리 Macrobenchmark 테스트는 앱 자체와 분리된 프로세스에서 실행됩니다. 이는 앱 프로세스를 중지하고 DEX 바이트 코드를 기계어 코드로 컴파일하는 등의 작업을 위해 필요합니다.
UIAutomator 라이브러리를 사용하거나 테스트 프로세스에서 타겟 앱을 제어할 수 있는 다른 메커니즘을 사용하여 앱 상태를 유도할 수 있습니다.
Espresso 또는 ActivityScenario
는 앱과 공유된 프로세스에서 실행되리라 예상하기 때문에 Macrobenchmark에서는 사용할 수 없습니다.
다음 예에서는 관련 리소스 ID를 사용하여 RecyclerView
를 찾고 여러 번 아래로 스크롤합니다.
@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) }
}
}
@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;
}
);
}
벤치마크에서는 UI를 스크롤하지 않아도 됩니다. 대신 애니메이션 등을 실행할 수 있습니다. 또한 UI Automator를 특별히 사용할 필요가 없습니다. Jetpack Compose에서 생성된 프레임을 포함하여 뷰 시스템에서 프레임이 생성되는 한 성능 측정항목이 수집됩니다.
앱의 내부로 이동
외부에서 직접 액세스할 수 없는 앱 부분을 벤치마킹하려는 경우가 있습니다. 예를 들어 exported=false
로 표시된 내부 활동에 액세스하거나, Fragment
로 이동하거나, 일부 UI를 스와이프하여 제거하는 것일 수 있습니다. 벤치마크는 사용자처럼 앱의 이러한 부분으로 수동으로 이동해야 합니다.
수동으로 이동하려면 setupBlock{}
내의 코드를 변경하여 버튼 탭 또는 스와이프와 같은 원하는 효과를 포함합니다. measureBlock{}
에는 실제로 벤치마킹하려는 UI 조작만 포함됩니다.
@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)
)
}
@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 -> {
// ...
}
);
}
현재 추천 자료가 없습니다.
Google 계정에 로그인해 보세요.