29、Kotlin测试:单元测试框架、JUnit与Kotlin Test、MockK库、协程测试
说实话,很多Kotlin开发者写代码时很爽,一到测试就头疼。我早期带团队时也踩过这个坑——代码写得飞起,测试覆盖率惨不忍睹。后来我慢慢意识到,测试不是负担,而是代码质量的护城河。今天咱们就聊聊Kotlin生态里那些好用的测试工具。
单元测试框架:JUnit 5 与 Kotlin Test
先说说最基础的。JUnit 5 在 Java 世界里是标配,到了 Kotlin 这边依然能打。不过我个人更推荐 Kotlin Test,它跟 Kotlin 的语法糖配合得更丝滑。
举个例子,JUnit 5 里你写个测试类得这么来:
class CalculatorTest {
private val calculator = Calculator()
@Test
fun `加法测试`() {
assertEquals(4, calculator.add(2, 2))
}
}
用 Kotlin Test 的话,写法更自然:
class CalculatorTest : StringSpec({
"加法测试" {
calculator.add(2, 2) shouldBe 4
}
})
看到区别了吗?shouldBe 这种中缀表达式读起来就像在说人话。我在项目中经常用 StringSpec 或 BehaviorSpec,因为测试用例的描述本身就是文档。
MockK 库:Kotlin 专属的 Mock 利器
Mockito 在 Java 里很流行,但到了 Kotlin 就有点水土不服——final 类、扩展函数、协程……Mockito 处理起来很别扭。这时候 MockK 就派上用场了。
MockK 是专门为 Kotlin 设计的 Mock 框架。我当年从 Mockito 切换到 MockK 时,最大的感受就是:终于不用写那么多样板代码了。
看个例子:
class UserServiceTest : StringSpec({
val userRepo = mockk<UserRepository>()
val userService = UserService(userRepo)
"获取用户信息" {
every { userRepo.findById(1) } returns User(1, "张三")
val result = userService.getUser(1)
result.name shouldBe "张三"
verify { userRepo.findById(1) }
}
})
这里有几个关键点:
mockk()创建 Mock 对象every { ... } returns ...定义行为verify { ... }验证调用
协程测试:runTest 与 TestScope
协程测试是 Kotlin 测试里最让人头疼的部分。我记得第一次写协程测试时,死活跑不过,后来才发现是 测试框架没感知到协程的调度。
Kotlin 官方提供了 kotlinx-coroutines-test 库,核心就是 runTest 和 TestScope。
看个实际例子:
class CoroutineServiceTest : StringSpec({
"异步加载数据" {
val service = CoroutineService()
runTest {
val result = service.loadData()
result shouldBe "数据加载完成"
}
}
})
runTest 会自动处理协程的调度,让测试变成同步执行。但要注意,如果你的代码里有 delay(),runTest 会跳过等待时间,直接执行后续代码。
再复杂一点的情况,比如测试超时或并发:
runTest {
withTimeout(1000) {
val result = withContext(Dispatchers.IO) {
// 模拟耗时操作
delay(500)
"完成"
}
result shouldBe "完成"
}
}
知识体系总览
下面这张图总结了本章的核心内容,方便你快速回顾:
实战建议:测试金字塔
说了这么多工具,最后聊聊策略。我一般遵循 测试金字塔 原则:
| 层级 | 比例 | 工具 | 说明 |
|---|---|---|---|
| 单元测试 | 70% | Kotlin Test + MockK | 测试单个类或函数,速度快 |
| 集成测试 | 20% | JUnit 5 + TestContainers | 测试数据库、网络等外部依赖 |
| 端到端测试 | 10% | 自定义框架 | 模拟真实用户场景 |
说白了,单元测试是性价比最高的。你花 20% 的时间写单元测试,能发现 80% 的 bug。我见过太多团队一上来就搞端到端测试,结果维护成本高、跑得慢,最后测试用例全废了。
好了,关于 Kotlin 测试的核心内容就这些。记住:测试不是可选项,是必需品。从今天开始,给你的每个函数都配上测试吧。