测试金字塔
大量快而廉价的单元测试打底,少量集成居中,更少但更慢的 UI 测试封顶。重心放单测,性价比最高。
test/ 本地 JVM 单测(快)、androidTest/ 设备 UI 测试(慢)、test/ 中可用 Robolectric 模拟框架。
JUnit 单元测试
用 @Test 标注测试方法,assertEquals 等断言验证行为。纯逻辑放在 test/ 下,毫秒级运行。
class CartTest {
@Test fun add_increasesTotal() {
val cart = Cart()
cart.add(Product("A", 10)); cart.add(Product("B", 5))
assertEquals(15, cart.total)
}
}MockK 替身
MockK 是 Kotlin 友好的 Mock 框架,支持 suspend、coroutine、私有方法,比 Mockito 更适合 Kotlin。
@MockK lateinit var repo: UserRepository
@RelaxedMockK lateinit var analytics: Analytics
@Before fun setup() = MockKAnnotations.init(this, relaxed = true)
@Test fun load_callsRepo() = runTest {
coEvery { repo.users() } returns emptyList()
val vm = HomeViewModel(repo, analytics)
vm.load()
coVerify { repo.users() }
}ViewModel 测试
用 runTest + StandardTestDispatcher 控制协程调度,断言 StateFlow 取值。
@Test fun login_success_setsState() = runTest {
val vm = LoginViewModel(fakeRepo)
vm.login("u", "p")
assertTrue(vm.state.value is LoginState.Success)
}UI 测试
Espresso 测 View 系统、Compose UI Test 测 Compose,通过资源 id 模拟点击并断言。
composeTestRule.setContent { Greeting("X") }
composeTestRule.onNodeWithText("X").assertIsDisplayed()启动真机级 App,分钟级。只在 CI 跑核心链路,细节交给单测。
基准测试
Macrobenchmark 测量启动、滚动帧率;Microbenchmark 测量小函数耗时,防回归。
CI 是最后闸,先本地跑通相关测试再把反馈循环缩到最短。
Profiler 调试
Android Studio Profiler 看 CPU、内存、网络、能耗。卡顿用 CPU 记录,泄漏用内存堆转储(HPROF)。
常见陷阱
多因触碰真实网络/数据库或启动 App 生命周期。用 MockK 替换外部依赖,把被测单元缩到纯逻辑。
测试协程需用 runTest 与 TestDispatcher,否则默认调度器会抛主线程限制异常。