很多 Android 项目测试少,不是因为不想写,而是不知道测什么、怎么测。测试金字塔可以帮你决定投入比例。
一、测试金字塔三层
/\
/ \ UI 测试(少、慢、贵)
/____\
/ \ 集成测试(中)
/________\
/ \ 单元测试(多、快、便宜)
/____________\
二、单元测试写什么
class DiscountUseCaseTest {
@Test
fun `price above 100 gets 10 percent off`() {
val useCase = DiscountUseCase()
assertEquals(90.0, useCase.apply(100.0), 0.01)
}
}
单元测试适合:
纯函数计算
业务规则验证
数据转换逻辑
ViewModel 状态变化
三、集成测试:测模块协作
@RunWith(AndroidJUnit4::class)
@HiltAndroidTest
class UserRepositoryTest {
@get:Rule
val hiltRule = HiltAndroidRule(this)
@Inject
lateinit var repository: UserRepository
@Test
fun fetchUser_returnsEntity() = runTest {
val user = repository.fetchUser("123")
assertNotNull(user)
}
}
集成测试验证数据库、网络、Repository 之间的协作,需要真实 Android 环境或 Robolectric。
四、UI 测试:测用户路径
@Test
fun login_success_navigatesToHome() {
onView(withId(R.id.phoneInput)).perform(typeText("13800138000"))
onView(withId(R.id.codeInput)).perform(typeText("123456"))
onView(withId(R.id.loginBtn)).perform(click())
onView(withId(R.id.homeRoot)).check(matches(isDisplayed()))
}
Compose 测试:
composeTestRule.setContent { LoginScreen() }
composeTestRule.onNodeWithText("登录").performClick()
composeTestRule.onNodeWithTag("homeRoot").assertIsDisplayed()
五、测试策略 checklist
优先写单元测试:成本低、回报高
不要把所有逻辑都放到 UI 层测:UI 测试慢且容易 flaky
用 Fake 代替 Mock:测行为比测调用次数更重要
测试命名要能读:
price_above_100_gets_10_percent_off比testDiscount好CI 里跑测试:本地跑单元,CI 跑全部
小结
测试金字塔告诉我们:单元测试占大头
ViewModel 和 UseCase 是单元测试的重点
Repository 适合集成测试
UI 测试只覆盖核心用户路径
下一篇,我们聊聊 Navigation 组件:深层链接、多栈与跨模块导航。
参考阅读
引用链接
[1]Android 测试文档: https://developer.android.com/training/testing
[2]Test Doubles: Fakes, Mocks, Stubs: https://developer.android.com/training/testing/fundamentals/test-doubles