测试与性能
测试与性能 · androidx.test
Benchmark 与 Macrobenchmark:先选测量边界
区分进程内小代码测量与跨进程完整用户流程。
最后更新 2026-08-01
复制即用
Microbenchmark(同模块/进程,小代码边界):
@get:Rule
val benchmarkRule = BenchmarkRule()
@Test
fun parseDocument() = benchmarkRule.measureRepeated {
parser.parse(source)
}Macrobenchmark(独立 APK 驱动完整流程):
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun coldStart() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD,
setupBlock = { pressHome() },
) {
startActivityAndWait()
}两种 Benchmark 对比
| 维度 | Microbenchmark | Macrobenchmark |
|---|---|---|
| 进程 | 与测试代码同模块/进程 | 独立测试 APK 驱动目标应用 |
| 适合 | 算法、布局计算、序列化 | 启动、滚动、帧时间、完整路径 |
| 度量 | BenchmarkRule.measureRepeated | MacrobenchmarkRule + Metrics |
| 噪声控制 | 环境隔离 | Release/profileable、物理设备、固定温控 |
常用 Metrics
| Metric | 用途 |
|---|---|
StartupTimingMetric | 冷/温/热启动时间 |
FrameTimingMetric | 帧时间(滚动流畅度) |
TraceSectionMetric | 指定 trace section 耗时 |
MemoryUsageMetric | 内存占用 |
fun scrollTest() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(FrameTimingMetric(), TraceSectionMetric("MySection")),
iterations = 10,
startupMode = StartupMode.WARM,
) {
startActivityAndWait()
device.executeShellCommand("input swipe 500 1500 500 300 100")
}常见陷阱
- 微基准塞网络/磁盘:环境噪声大于真正差异。
- 无意义迭代次数:Release/profileable 构建、物理设备、固定温控比 iteration 更重要。
- measure block 混入前置操作:
setupBlock只建状态,measure 只计时。 - 模拟器跑基准:性能数据无参考价值。
要点
- 先选测量边界:小代码微基准,完整流程宏基准。
setupBlock建前置状态;measure block 只保留要计时的行为。- Release/profileable + 物理设备 + 固定温控决定结果可信度。
- 帧时间/启动/内存分别用对应 Metric。