当前位置: 首页 > article >正文

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 中添加依赖:

// 模块级 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 对象
val service = mockk<MyService>() // 创建 Mock 对象
3.2 设置行为 (Stubbing)
// 模拟方法返回值
every { service.fetchData(any()) } returns "Mocked Data"// 模拟抛出异常
every { service.fail() } throws RuntimeException("Error")
3.3 验证调用
service.fetchData(123)
verify { service.fetchData(123) } // 验证方法是否被调用// 验证调用次数
verify(exactly = 1) { service.fetchData(any()) }
3.4 参数匹配器
// 匹配任何参数
every { service.fetchData(any()) } returns "Data"// 捕获参数
val slot = slot<Int>()
every { service.saveData(capture(slot)) } just Runsservice.saveData(123)
assert(slot.captured == 123)

4. 高级用法

4.1 模拟静态方法与对象声明
// Mock object 单例
object Singleton {fun doWork() = "Real"
}mockkObject(Singleton)
every { Singleton.doWork() } returns "Mocked"// Mock 静态方法
mockkStatic(MyUtils::class)
every { MyUtils.format(any()) } returns "Formatted"

清理资源

@After
fun tearDown() {unmockkAll() // 或 unmockkObject(Singleton)
}
4.2 模拟构造函数
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 处理挂起函数:

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:部分模拟真实对象
val spy = spyk<RealClass>() // 默认调用真实方法every { spy.mockedMethod() } returns "Mocked"

5. Android 特有场景

5.1 测试 ViewModel
class MyViewModel(private val repo: Repository) : ViewModel() {private val _data = MutableLiveData<String>()val data: LiveData<String> = _datafun load() {viewModelScope.launch {_data.value = repo.fetchData()}}
}// 测试代码
@Test
fun testViewModel() = runTest { // 使用 TestCoroutineDispatcherval repo = mockk<Repository>()coEvery { repo.fetchData() } returns "Test Data"val viewModel = MyViewModel(repo)viewModel.load()// 处理 LiveDataval observer = mockk<Observer<String>>()viewModel.data.observeForever(observer)verify(timeout = 1000) { observer.onChanged("Test Data") }
}
5.2 处理 Context
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 策略,确保测试既简洁又可靠。

http://www.lryc.cn/news/2379659.html

相关文章:

  • C# lock
  • 《算法导论(第4版)》阅读笔记:p83-p85
  • Go 后端中双 token 的实现模板
  • 【拥抱AI】Deer-Flow字节跳动开源的多智能体深度研究框架
  • 第六天——贪心算法——字符串分隔
  • Python 条件语句详解
  • 前端获取用户的公网 IP 地址
  • 在Maven中替换文件内容的插件和方法
  • 符合Python风格的对象(再谈向量类)
  • 云电竞服务器 工作原理
  • 【数据结构】线性表--队列
  • [Vue3]语法变动
  • Ubuntu服务器开启SNMP服务 监控系统配置指南 -优雅草星云智控简易化操作
  • linux本地部署ollama+deepseek过程
  • 从零开始实现大语言模型(十五):并行计算与分布式机器学习
  • OpenCV进阶操作:指纹验证、识别
  • 网络安全-等级保护(等保) 2-5 GB/T 25070—2019《信息安全技术 网络安全等级保护安全设计技术要求》-2019-05-10发布【现行】
  • 3D生成新突破:阶跃星辰Step1X-3D开源,可控性大幅提升
  • MySQL数据类型之VARCHAR和CHAR使用详解
  • 数字人 LAM 部署笔记
  • 《Docker 入门与进阶:架构剖析、隔离原理及安装实操》
  • 基于Akamai云计算平台的OTT媒体点播转码解决方案
  • 【MySQL】02.数据库基础
  • 选错方向太致命,华为HCIE数通和云计算到底怎么选?
  • 经典启发算法【早期/启发式/HC爬山/SA模拟退火/TS禁忌搜/IA免疫 思想流程举例全】
  • IntraWeb 16.0.2 + Bootstrap 4 居中布局实战(附源码+效果图)
  • Spring 框架中适配器模式的五大典型应用场景
  • 【Java ee初阶】jvm(3)
  • C 语言多维数组:定义、初始化与访问的深度解析
  • 浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)