如何编写Kotlin单元测试测试内部调用其他函数的方法
问题根因
if分支无法进入的直接原因是执行到判断逻辑时,inventoryInfo始终为null或空集合,常见触发场景:
- 未正确Mock静态工具类
UtilityFunctions的方法,测试运行时要么走真实逻辑拿到不符合预期的返回值,要么Mock框架默认返回null - 传入的测试入参
message不符合工具类解析规则,即使走真实解析逻辑也拿不到非空的inventoryInfo - 前序步骤(
sqsQPayloadExtractor调用、返回值取索引)抛出异常,被外层catch吞掉,根本没走到if判断逻辑
分步解决方法
1. 选择适配Kotlin的静态Mock方案
Kotlin中的静态方法、顶层函数、伴生对象方法无法用原生Mockito直接Mock,优先选Kotlin专属测试框架MockK,对静态方法、空安全、扩展函数的适配更完善;如果坚持用Mockito,需要引入mockito-inline依赖(mockito-core 3.4+版本已内置该能力)支持静态Mock。
- MockK静态Mock写法:
// 测试类中声明静态Mock mockkStatic(UtilityFunctions::class) // 单测执行完成后解绑静态Mock,避免影响其他用例 @AfterEach fun tearDown() { unmockkStatic(UtilityFunctions::class) }
- Mockito-inline静态Mock写法:
// 用try-with-resources自动关闭静态Mock try (MockedStatic<UtilityFunctions> mockedStatic = Mockito.mockStatic(UtilityFunctions::class.java)) { // 此处编写Mock规则与测试执行逻辑 }
2. 按分支场景构造Mock返回值
要进入if分支,必须保证extractInventoryType返回非空且长度至少为2的集合——因为分支内直接取了inventoryInfo[0]和inventoryInfo[1],集合长度不足会抛出数组越界异常。
覆盖if分支的核心Mock逻辑参考(以MockK为例):
@Test fun `process when inventoryInfo is valid should call startProcess`() { // 构造测试数据 val testMsg = "test-sqs-raw-message" val mockSqsPayload = listOf("test-payload-body", "test-bucket-name") val mockInventoryInfo = listOf("inventory-type", "inventory-file-path") // 初始化依赖与待测试类 val mockProcessService = mockk<TransformerProcessService>() val testInstance = YourProcessorClass(mockProcessService) // 替换为你自己的待测试类名 // 配置Mock规则 every { UtilityFunctions.sqsQPayloadExtractor(testMsg) } returns mockSqsPayload every { UtilityFunctions.extractInventoryType(mockSqsPayload[0]) } returns mockInventoryInfo every { mockProcessService.startProcess(any(), any(), any(), any()) } just Runs // 执行待测试方法 testInstance.process(testMsg) // 验证if分支逻辑确实触发 verify(exactly = 1) { mockProcessService.startProcess( mockSqsPayload[0], mockInventoryInfo[0], mockInventoryInfo[1], mockSqsPayload[1] ) } }
要覆盖else分支,只需要把extractInventoryType的Mock返回值改为null或者空集合即可:
every { UtilityFunctions.extractInventoryType(mockSqsPayload[0]) } returns null // 或 returns emptyList()
3. 常见避坑点
- 不要遗漏
sqsQPayloadExtractor的Mock:如果该方法Mock失败返回null,后续取sqsPayloadInfo[0]会直接触发空指针,被外层catch块捕获,根本到不了if判断 - 注意Kotlin空安全规则:如果
extractInventoryType源码定义的返回值是不可空类型(没有带?修饰),Mock时强行返回null会直接抛空指针,先确认方法签名的可空性 - 你当前代码的catch块会吞掉所有异常:如果测试执行后既没走if也没走else,先在catch块加断点,大概率是前序逻辑抛了异常(比如数组越界、Mock未生效、依赖未注入)
- 长期优化建议:尽量避免直接静态调用工具类方法,改为通过构造函数注入依赖,后续测试不需要依赖静态Mock能力,代码可测试性更高
内容的提问来源于stack exchange,提问作者SamDev
相关产品推荐
相关产品推荐

