Kotlin Android单元测试MockK指南

目录

  1. MockK 简介
  2. 环境配置
  3. 基础用法
  4. 高级用法
  5. Android 特有场景
  6. 最佳实践

1. MockK 简介

MockK 是一个专为 Kotlin 设计的 Mocking 框架,支持协程、扩展函数、对象声明(object)等 Kotlin 特性。相比 Mockito,它提供更自然的 Kotlin API,解决了 final 类无法 Mock 的问题。

核心优势

  • 原生支持 Kotlin 特性(如协程、object 单例)。
  • 简洁的 DSL 语法。
  • 支持静态方法、构造函数 Mock。

2. 环境配置

build.gradle 中添加依赖:

kotlin 复制代码
// 模块级 build.gradle
dependencies {
    testImplementation "io.mockk:mockk:1.13.8"        // 基础库
    testImplementation "io.mockk:mockk-agent-jvm:1.13.8" // 解决某些 JDK 版本兼容性问题
    testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" // JUnit 5(可选)
}

注意 :若使用 JUnit 4,需添加 testImplementation "io.mockk:mockk-android:1.13.8"


3. 基础用法

3.1 创建 Mock 对象
kotlin 复制代码
val service = mockk<MyService>() // 创建 Mock 对象
3.2 设置行为 (Stubbing)
kotlin 复制代码
// 模拟方法返回值
every { service.fetchData(any()) } returns "Mocked Data"

// 模拟抛出异常
every { service.fail() } throws RuntimeException("Error")
3.3 验证调用
kotlin 复制代码
service.fetchData(123)
verify { service.fetchData(123) } // 验证方法是否被调用

// 验证调用次数
verify(exactly = 1) { service.fetchData(any()) }
3.4 参数匹配器
kotlin 复制代码
// 匹配任何参数
every { service.fetchData(any()) } returns "Data"

// 捕获参数
val slot = slot<Int>()
every { service.saveData(capture(slot)) } just Runs

service.saveData(123)
assert(slot.captured == 123)

4. 高级用法

4.1 模拟静态方法与对象声明
kotlin 复制代码
// Mock object 单例
object Singleton {
    fun doWork() = "Real"
}

mockkObject(Singleton)
every { Singleton.doWork() } returns "Mocked"

// Mock 静态方法
mockkStatic(MyUtils::class)
every { MyUtils.format(any()) } returns "Formatted"

清理资源

kotlin 复制代码
@After
fun tearDown() {
    unmockkAll() // 或 unmockkObject(Singleton)
}
4.2 模拟构造函数
kotlin 复制代码
class MyHelper(val config: String)

mockkConstructor(MyHelper::class)
every { anyConstructed<MyHelper>().config } returns "Mocked Config"

val helper = MyHelper("Real")
assert(helper.config == "Mocked Config")
4.3 协程支持

使用 coEverycoVerify 处理挂起函数:

kotlin 复制代码
class Repository {
    suspend fun loadData() = "Real Data"
}

val repo = mockk<Repository>()
coEvery { repo.loadData() } returns "Mocked Data"

runBlocking {
    val data = repo.loadData()
    assert(data == "Mocked Data")
    coVerify { repo.loadData() }
}
4.4 Spy:部分模拟真实对象
kotlin 复制代码
val spy = spyk<RealClass>() // 默认调用真实方法

every { spy.mockedMethod() } returns "Mocked"

5. Android 特有场景

5.1 测试 ViewModel
kotlin 复制代码
class MyViewModel(private val repo: Repository) : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data

    fun load() {
        viewModelScope.launch {
            _data.value = repo.fetchData()
        }
    }
}

// 测试代码
@Test
fun testViewModel() = runTest { // 使用 TestCoroutineDispatcher
    val repo = mockk<Repository>()
    coEvery { repo.fetchData() } returns "Test Data"

    val viewModel = MyViewModel(repo)
    viewModel.load()

    // 处理 LiveData
    val observer = mockk<Observer<String>>()
    viewModel.data.observeForever(observer)
    verify(timeout = 1000) { observer.onChanged("Test Data") }
}
5.2 处理 Context
kotlin 复制代码
val context = mockk<Context>()
val res = mockk<Resources>()

every { context.resources } returns res
every { res.getString(any()) } returns "Mocked String"

6. 最佳实践

  1. 避免过度 Mock:仅 Mock 外部依赖(如网络、数据库),不要 Mock 被测类内部行为。
  2. 使用清晰命名 :如 userRepositoryMock 替代 mockk<Repository>()
  3. 及时清理 :在 @After 中调用 unmockkAll() 避免测试间污染。
  4. 组合使用工具 :结合 TruthTurbine 等库提升断言可读性。
  5. 优先使用真实对象:当依赖简单且无副作用时,直接使用真实对象而非 Mock。

实际开发中,建议结合具体场景选择最合适的 Mock 策略,确保测试既简洁又可靠。

相关推荐
哲科软件8 小时前
跨平台开发的抉择:Flutter vs 原生安卓(Kotlin)的优劣对比与选型建议
android·flutter·kotlin
jyan_敬言15 小时前
【C++】string类(二)相关接口介绍及其使用
android·开发语言·c++·青少年编程·visual studio
程序员老刘15 小时前
Android 16开发者全解读
android·flutter·客户端
福柯柯16 小时前
Android ContentProvider的使用
android·contenprovider
不想迷路的小男孩16 小时前
Android Studio 中Palette跟Component Tree面板消失怎么恢复正常
android·ide·android studio
餐桌上的王子16 小时前
Android 构建可管理生命周期的应用(一)
android
菠萝加点糖16 小时前
Android Camera2 + OpenGL离屏渲染示例
android·opengl·camera
用户20187928316716 小时前
🌟 童话:四大Context徽章诞生记
android
yzpyzp16 小时前
Android studio在点击运行按钮时执行过程中输出的compileDebugKotlin 这个任务是由gradle执行的吗
android·gradle·android studio
aningxiaoxixi16 小时前
安卓之service
android