Kotlin中使用Mockito测试Micronaut RxHttpClient空指针如何解决
问题根因
该空指针异常由Mockito规则未命中、返回默认值null导致,具体触发场景包括以下几种:
- Micronaut的
RxHttpClient是final类,未引入mockito-inline依赖时,Mockito无法正常mock final类,所有方法调用默认返回null - mock时使用具体的
HttpRequest.GET实例做参数匹配,实际代码中创建的HttpRequest是新实例,默认equals匹配未命中 - mock的
retrieve方法重载和业务代码实际调用的重载不匹配,规则未触发 - 实例化
Exchange类时未正确注入mock的RxHttpClient实例,httpClient字段本身为null
修复方案
1. 基础依赖配置
引入mockito-inline支持final类mock,推荐搭配mockito-kotlin简化Kotlin场景下的API调用:
// Gradle 依赖配置示例 testImplementation("org.mockito:mockito-inline:5.6.0") testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
2. 调整Mock规则匹配逻辑
使用Mockito参数匹配器替代具体实例匹配,确保规则命中:
- 通用匹配用
any()匹配任意HttpRequest实例 - 需要精准校验路径时用
argThat()做自定义路径匹配
3. 完整测试示例
import io.micronaut.http.HttpRequest import io.reactivex.Flowable import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test import org.mockito.kotlin.* class ExchangeTest { // 初始化mock的RxHttpClient private val mockHttpClient: RxHttpClient = mock() // 构造业务类,传入mock的httpClient private val exchange = Exchange(mockHttpClient) @Test fun `getSymbols returns correct symbol list`() = runTest { // 构造预设返回数据 val testSymbols = listOf(Symbol("BTCUSDT"), Symbol("ETHUSDT")) val testExchangeInfo = ExchangeInfo(testSymbols) // 配置mock规则 whenever(mockHttpClient.retrieve( // 精准匹配GET请求且路径以/symbols结尾 argThat<HttpRequest<*>> { it.method.name == "GET" && it.path.endsWith("/symbols") }, eq(ExchangeInfo::class.java) )).thenReturn(Flowable.just(testExchangeInfo)) // 执行测试&断言 val result = exchange.getSymbols() assert(result == testSymbols) } }
额外注意事项
- 建议
Exchange类使用构造注入注入RxHttpClient,避免字段注入需要反射赋值的问题 - 如果使用JUnit5注解驱动Mock,测试类需要添加
@ExtendWith(MockitoExtension::class)注解 - 校验业务代码中调用
retrieve的参数顺序、重载类型和mock的方法完全一致
内容的提问来源于stack exchange,提问作者val_dev29
相关产品推荐
相关产品推荐

