KMM(Kotlin多平台移动)网络调用单元测试实现求助
KMM跨平台网络单元测试问题解决方案
问题根源分析
- commonTest不等待异步请求完成:你的
testApi方法内部创建了独立的CoroutineScope,runBlocking无法追踪该作用域内的协程执行,导致测试直接走完流程,不等网络请求返回。 - Android仪器测试网络错误:你请求的
jsonplaceholder.typicode.com用的是HTTP明文协议,Android 9+默认禁止明文流量,而仪器测试的Manifest可能未配置相关允许项,导致域名解析失败。
一、重构testApi方法,实现协程作用域可注入
把内部硬编码的CoroutineScope改成参数传入,让测试代码可以控制协程的生命周期:
// 修改后的testApi方法 fun testApi( coroutineScope: CoroutineScope, // 新增作用域参数 success: () -> Unit, failure: (Error) -> Unit ) { val manager = getAuthorizationHTTPManager("jsonplaceholder.typicode.com", false) if (manager == null) { val error = BLError.error(BLErrorCodes.consumerCloudPostOAuthFailed, "Unable to create a session manager") BLLog.logError(error) failure(error) return } // 使用传入的作用域启动协程,不再自行创建 coroutineScope.launch(Dispatchers.IO) { try { val response = manager.get("/posts") Napier.d(response.body<String>().toString()) if(response.status.value in 200 .. 299){ success() } else { val json = JsonObject(response.body()) val error = BLError.error(BLErrorCodes.consumerCloudPostOAuthFailed, json["error"].toString()) failure(error) } } catch (e: Exception) { val error = BLError.error(BLErrorCodes.consumerCloudPostOAuthFailed, e.toString()) failure(error) } } }
业务代码中调用时,传入对应生命周期的作用域即可(比如Android端用viewModelScope,iOS端用自定义的作用域):
// Android业务代码示例 testApi(viewModelScope, success = { /* 成功逻辑 */ }, failure = { /* 失败逻辑 */ })
二、修复commonTest异步等待问题
使用kotlinx-coroutines-test库的runTest方法,它会自动等待测试作用域内的所有协程执行完毕。
1. 添加测试依赖
在shared模块的build.gradle.kts中添加协程测试库:
sourceSets["commonTest"].dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3") // 可替换为最新版本 }
2. 编写测试代码
import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertNull import kotlin.test.assertTrue class CommonApiTest { private val consumerCloud = YourConsumerCloudInstance() // 替换为你的实例 @Test fun testApiSuccess() = runTest { var isSuccess = false var error: Error? = null consumerCloud.testApi( coroutineScope = this, // 传入runTest提供的TestScope success = { isSuccess = true }, failure = { error = it } ) // 断言结果 assertNull(error) assertTrue(isSuccess) } }
runTest会自动阻塞直到所有子协程执行完成,解决测试提前结束的问题。
三、修复Android仪器测试网络错误
1. 允许明文流量
在androidInstrumentedTest目录下的AndroidManifest.xml中添加配置,允许HTTP明文请求:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="your.package.name"> <!-- 替换为你的应用包名 --> <uses-permission android:name="android.permission.INTERNET"/> <application android:usesCleartextTraffic="true"> </application> </manifest>
2. 优化仪器测试代码(可选)
现在testApi支持传入作用域,仪器测试也可以用runTest替代CountDownLatch,代码更简洁:
import kotlinx.coroutines.test.runTest import org.junit.Test import kotlin.test.assertNull import kotlin.test.assertTrue class InstrumentedApiTest { private val consumerCloud = YourConsumerCloudInstance() @Test fun testApiSuccess() = runTest { var isSuccess = false var error: Error? = null consumerCloud.testApi( coroutineScope = this, success = { isSuccess = true }, failure = { error = it } ) assertNull(error) assertTrue(isSuccess) } }
额外建议
- 单元测试阶段推荐用MockK等工具Mock Ktor客户端,避免依赖真实服务器,提升测试稳定性和速度。
- 确保
getAuthorizationHTTPManager在测试环境中正确初始化Ktor客户端,没有错误配置baseUrl或禁用网络。
内容的提问来源于stack exchange,提问作者Ritika
相关产品推荐
相关产品推荐

