单元测试:优雅编写Kotlin单元测试
一、MockK简介
MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时,MockK能够帮助我们简化代码、提高测试覆盖率,并改善测试的可维护性。除了基本用法外,MockK还提供了许多额外的功能和灵活的用法,让我们能够更好地模拟对象行为、验证函数调用,并在测试中处理更复杂的场景。本文将深入探索MockK框架,介绍其基本用法以及一些额外的高级特性,助力开发者更优雅地编写Kotlin单元测试。
二、基本用法
在开始使用 MockK 之前,我们需要将其库添加到项目的依赖中。然后,我们可以使用 mockk 函数创建模拟对象,使用 every 函数来定义模拟对象的行为。例如,我们可以模拟一个返回固定值的函数:
val mockObject = mockk<MyClass>()every { mockObject.someFunction() } returns "Mocked Result"
MockK 还提供了其他功能,如参数匹配、捕获函数调用参数等,以满足不同的测试需求。
2.1 参数匹配器
MockK 允许我们在定义模拟行为时使用参数匹配器,以便更灵活地匹配不同的参数。例如,我们可以使用 any() 匹配器来模拟接受任意参数的方法调用:
every { mockObject.someMethod(any()) } returns "Mocked Result"
MockK 还提供了其他匹配器,如 eq()(精确匹配)、capture()(捕获参数值)等,以满足更具体的匹配需求。
2.2 验证函数调用
除了定义模拟行为,MockK 还可以验证模拟对象的函数调用情况。通过使用 verify 函数,我们可以检查函数是否按预期调用了指定的次数:
verify { mockObject.someMethod() }
MockK 还支持验证函数调用的参数匹配、调用顺序和调用时间间隔等。
2.3 偏函数模拟
MockK 还支持偏函数模拟,这意味着我们可以模拟函数的部分行为,而不是完全替代它。这对于测试部分函数逻辑或处理不同情况的分支很有用。我们可以使用 answers 块来实现偏函数模拟:
every { mockObject.someMethod(any()) } answers { originalCall(it.invocation.args.first()) }
在上述示例中,我们将传递给模拟函数的参数作为原始函数的一部分,以实现偏函数行为。
2.4 模拟对象的构造函数
MockK 不仅可以模拟普通的对象行为,还可以模拟对象的构造函数。这使得在测试中模拟和控制对象的创建过程成为可能,从而更好地隔离和测试被测单元。我们可以使用 mockkConstructor 和 unmockkConstructor 函数来模拟和取消模拟构造函数。
mockkConstructor(MyClass::class)every { anyConstructed<MyClass>().someMethod() } returns "Mocked Result"// 执行测试代码unmockkConstructor(MyClass::class)
在上述示例中,我们模拟了 MyClass 的构造函数,并定义了模拟对象的行为,然后在测试代码执行完毕后取消模拟。
2.5 高阶用法
i. 模拟Lambda表达式的行为
在模拟Lambda表达式的行为时,MockK提供了灵活而直观的API。我们可以使用mockk函数来创建一个Lambda表达式的模拟对象,并使用invoke函数定义模拟对象的行为。例如:
val lambdaMock: () -> Unit = mockk()every { lambdaMock.invoke() } just Runs
在上述示例中,我们使用mockk函数创建了一个返回Unit的Lambda表达式的模拟对象lambdaMock。然后,通过every函数和invoke函数定义了模拟对象的行为,这里使用just Runs表示Lambda表达式被调用时不做任何操作。
ii. 捕获Lambda表达式的调用参数
MockK还支持捕获Lambda表达式的调用参数,以便在测试中进一步验证。通过使用captured函数和slot函数,我们可以捕获Lambda表达式在被调用时的参数值。例如:
val lambdaMock: (String) -> Unit = mockk()val capturedArg = slot<String>()every { lambdaMock.invoke(capture(capturedArg)) } just Runsverify { lambdaMock.invoke(any()) }assertEquals(expectedValue, capturedArg.captured)
在上述示例中,我们创建了一个接受String参数的Lambda表达式的模拟对象lambdaMock。通过使用slot函数创建了一个参数槽capturedArg,并在模拟对象的行为定义中使用capture函数捕获参数值。然后,通过verify函数和captured函数验证模拟对象的调用,以及使用assertEquals函数对捕获的参数进行断言。
通过引入这些额外的用法,可以让读者更全面地了解 MockK 框架的功能和灵活性,从而更好地应用于他们的单元测试工作中。这些功能扩展为测试人员提供了更多选项,以便根据实际需求模拟和验证代码行为。
三、MockK框架总结
MockK 框架为 Kotlin 单元测试带来了很多便利。它简化了模拟对象的创建和管理,使得编写可靠的单元测试变得更加轻松。通过 MockK,我们可以模拟对象的行为、捕获函数调用参数、模拟 lambda 表达式等。它提供了丰富的功能和灵活性,使我们能够针对不同的测试场景进行适当的模拟和验证。
除了基本用法和高阶使用外,MockK 还支持与其他测试框架(如JUnit、Spek)和依赖注入框架(如Koin、Dagger)的集成,使得整个测试过程更加完善和一致。
在开发过程中,使用 MockK 框架进行单元测试可以带来许多好处,包括增加代码可靠性、减少依赖关系、提高测试覆盖率等。它使得编写和维护测试代码变得更加高效和可靠。
以下是 MockK 框架的一些优点和建议的使用场景:
1. 简化测试代码:MockK 提供了简洁而直观的 API,使得创建和管理模拟对象变得容易。它的语法清晰简洁,可以快速定义模拟对象的行为和预期结果,从而减少冗余的测试代码。
2. 模拟复杂场景:MockK 不仅可以模拟普通的对象行为,还可以处理更复杂的场景,如模拟 lambda 表达式、捕获函数调用参数等。这使得在测试中处理回调函数、异步操作或依赖其他组件的情况变得更加容易。
3. 支持依赖注入框架:MockK 可以与常见的依赖注入框架(如Koin、Dagger)集成,使得在单元测试中模拟依赖项变得更加便捷。通过模拟依赖项,我们可以更好地隔离被测试单元的功能,并提供更可靠的测试环境。
4. 高度灵活和可扩展:MockK 提供了丰富的功能和灵活性,可以根据具体需求进行定制和扩展。它支持自定义行为、参数匹配器、调用顺序验证等,使得我们能够更精细地控制模拟对象的行为,并验证测试中的预期行为。
5. 配合其他测试框架:MockK 可以与常见的测试框架(如JUnit、Spek)无缝集成,使得整个测试流程更加统一和协调。通过结合不同的测试工具和框架,我们可以充分利用 MockK 的优势,并获得更全面的测试覆盖和准确的测试结果。
总之,MockK 框架是一款功能强大且易于使用的 Kotlin mocking 框架,它为单元测试提供了简化和增强的解决方案。通过使用 MockK,我们可以更轻松地编写和维护单元测试代码,提高测试覆盖率和代码质量,减少代码错误和缺陷。无论是简单的对象行为模拟还是复杂的回调函数处理,MockK 都能够满足我们的需求,并为我们的测试工作提供可靠的支持。因此,当您在编写 Kotlin 单元测试时,不妨考虑使用 MockK 框架,利用其丰富的功能和简洁的语法,为您的测试代码带来更高效和可维护的体验。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取
相关文章:
单元测试:优雅编写Kotlin单元测试
一、MockK简介 MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时,MockK能够帮助我们简化代码、提高测试覆盖率,并改善测试的可维护性。除了基本用法外,MockK还提供了许多额外的功能和灵活的用法,让我们能够…...
深度学习入门教学——卷积神经网络CNN
目录 一、CNN简介 一、输入层 二、卷积层 三、池化层 四、全连接层 一、CNN简介 1、应用领域 检测任务 分类与检索 超分辨率重构 2、卷积网络与传统网咯的区别 传统神经网络和卷积神经网络都是用来提取特征的。神经网络: 可以将其看作是一个二维的。卷积神经…...
【MySQL】MySQL系统变量(system variables)列表(mysqld --verbose --help的结果例)
文章目录 【MySQL】MySQL系统变量(system variables)列表(mysqld --verbose --help的结果例)mysqld --verbose --help的结果例参考 【免责声明】文章仅供学习交流,观点代表个人,与任何公司无关。 编辑|SQL和…...
Python学习之四 数据输入与输出
(一) 脚本编程 前面的章节,组要学习了一些简单的Python编程,使用的是交互式解释器,本章节将开始进行脚本编程。可以使用多种编辑器或者IDE完成编码,主要使用vim。 参考前续小节的写法,我们给a、b分别赋值3和5。 在终端运行程序后发现,没有任何输出。这就是本次我们将要…...
VBA技术资料MF51:VBA_在Excel中突出显示唯一值
【分享成果,随喜正能量】世间万物,因果循环不休,你的善心善行,都可能成为你的善缘善果。每天忆佛念佛,每天都在佛菩萨的加持下生活,自然吉祥如意,法喜充满。 。 我给VBA的定义:VBA是…...
Mqtt学习笔记--交叉编译移植(1)
简述 Mqtt目前在物联网行业的应用比较多,mqtt属于应用层的一个中间件,这个中间件实现消息的订阅发布机制。网上介绍Mqtt的实现原来的比较多,这里不细介绍。 其实在我们之前的产品中,自己也开发的有类似的中间件,除了具…...
Gateway的服务网关
Gateway服务网关 Gateway网关是我们服务的守门神,所有微服务的统一入口。 网关的核心功能特性: 请求路由 权限控制 限流 架构如下: gateway使用 引入依赖 创建gateway服务,引入依赖 <!--网关--> <dependency>…...
信息化发展18
存储技术 1 、存储分类 2 、常用存储模式的技术与应用对比: ( 1 ) 存储虚拟化( Storage Virtualization ) 是“ 云存储” 的核心技术之一。 它带给人们直接的好处是提高了存储利用率, 降低了存储成本, 简…...
TypeScript学习 + 贪吃蛇项目
TypeSCript简介 TypeScript是JavaScript的超集。它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。TS完全兼容JS,换言之,任何的JS代码都可以直…...
YOLO-NAS详细教程-介绍如何进行物体检测
对象检测是计算机视觉中的一项核心任务,可以检测和分类图像中的边界框。自从深度学习首次取得突破以来,它就以极快的速度获得普及和普及,并推动了医疗领域、监控、智能购物等众多公司的发展。考虑到它最终满足了两个基本需求,这一点也就不足为奇了端到端方式:找到所有当前…...
容器没有命令时,如何查看进程、容器executable file not found in $PATH: unknown
前言 当容器没有ps -ef命令时,可以通过以下的命令来查看容器的进程。 docker container top查看容器运行的进程(该命令很有用) #docker container top 命令用于查看容器运行的进程 #当容器里面没有ps -ef命令时,使用docker con…...
如何使用 Amazon EMR 在 Amazon EKS 上构建可靠、高效、用户友好的 Spark 平台
这是 SafeGraph 技术主管经理 Nan Zhu 与亚马逊云科技高级解决方案架构师 Dave Thibault 共同撰写的特约文章。 SafeGraph 是一家地理空间数据公司,管理着全球超过 4100 万个兴趣点(POI,Point of Interest),提供品牌隶…...
国产IDE如何获得捐赠和风险投资
有人在开发VB6 脚本工具,有人在开发VB6的插件,把VB6变成VSCODE界面模式,再加上NUGET,NPM等包管理器原理的在线组件、源码下载功能。 还有TWINBASIC几乎80%代替了VB6,radbasic一直封闭,听说也收到了不少众筹…...
【数学建模】清风数模正课5 相关性分析
相关系数 相关性分析的关键是计算相关系数,在本节课中将会介绍两种常用的相关系数:皮尔逊相关系数(Pearson)和斯皮尔曼相关系数(Spearman)。 它们可以用来衡量两个变量间相关性的大小,对于不同…...
Java设计模式:一、六大设计原则-03:里氏替换原则
文章目录 一、定义:里氏替换原则1.1 里氏替换原则1.2 里氏替换原则的作用 二、模拟场景:里氏替换原则三、违背方案:里氏替换原则3.1 工程结构3.2 储蓄卡和信用卡3.2.1 储蓄卡3.2.2 信用卡 3.3 单元测试3.3.1 储蓄卡测试3.3.2 信用卡测试 四、…...
jmeter 固定定时器
固定定时器(Constant Timer)是一个定时器元件,可以在线程组中的每个线程之间添加固定的延迟时间。固定定时器会对每个线程的执行进行一定的暂停。 聊一下和线程组中的调度器对线程组执行时长的影响: 相同: 都会影响线…...
【微服务部署】07-调用链追踪
文章目录 集成SkyWalking实现调用链追踪1. SkyWalking架构图2. 代码集成SkyWalking 集成SkyWalking实现调用链追踪 1. SkyWalking架构图 Receiver是SkyWalking的入口,支持gRPC和HTTP协议。 SkyWalking内部有分析和查询两个部分 存储方面SkyWalking支持Elasticsearc…...
【C++入门】命名空间、缺省参数、函数重载、引用、内联函数
👻内容专栏: C/C编程 🐨本文概括: C入门学习必备语法 🐼本文作者: 阿四啊 🐸发布时间:2023.9.3 前言 C是在C的基础之上,容纳进去了面向对象编程思想,并增加…...
c++ 学习之 构造函数的使用规则
上规则 // 默认情况下,c 编译器至少给一个类添加三个函数 //1.默认构造函数(无参,函数体为空) //2.默认析构函数 (无参 ,函数体为空) //3.默认拷贝函数,对其属性进行值拷贝 //构…...
C++操作符重载的注意事项
关于C操作符重载,可以用类内的成员运算符重载或友元函数。但是注意两个不能同时出现,不然编译出错。 #include<iostream> using namespace std; class Complex{public:Complex(int r0,int i0){real r;imag i;}//#if 0Complex operator(Complex …...
10 | Spark 查找每个单词的最大行号
假设你有一个包含文本行号和文本内容的RDD,现在你想找出每个单词出现在哪些行,并计算它们出现的最大行号。 需求是从包含文本行号和文本内容的RDD中找出每个单词出现在哪些行,并计算它们出现的最大行号。 具体需求如下: 数据输入: 代码从一个包含文本行号和文本内容的RD…...
CRE66365
CRE66365是一款高度集成的电流模式PWM控制IC,为高性能、低待机功耗和低成本的隔离型反激转换器。在正常负载条件下,AC输入高电压下工作在QR模式。为了最大限度地减少开关损耗,QR 模式下的最大开关频率被内部限制为 77kHz。当负载较低时&#…...
React hook 10种常见 Hook
React Hook是什么? React官网是这么介绍的: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 完全可选的 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不…...
图文详解PhPStudy安装教程
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 官方下载 请在PhPStudy官方网站下载安装文件,官方链接如下:https://m.xp.cn/linux.html;图示如下: 请下载PhPStudy安装文件…...
stable diffusion实践操作-hypernetworks
系列文章目录 本文专门开一节写hypernetworks的内容,在看之前,可以同步关注: stable diffusion实践操作 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、h…...
Win10搭建VisualSvn Server
Win10搭建VisualSvn Server 目录 Win10搭建VisualSvn Server一、下载VisualSvn Server安装包二、安装VisualSvn Server三、配置和使用VisualSVN Server四、添加用户及权限设定方法五、创建目录及配置权限 1、服务端:有集成了Subversion和Apache、安装使用非常简单且…...
Golang网络编程
Golang网络编程 网络编程简介网络编程协议网络分层模型TCP/IP协议什么是DNS套接字(Socket)客户端服务器模型TCP/UDP的区别HTTP协议会话sessionCookiehttpsHTTP请求格式HTTP响应格式http头信息http请求头信息http响应头信息HTTP状态码http内容类型和内容…...
详解vue3中ref和reactive用法和区别
vue3中ref和reactive区别 1、前言2、基本用法2.1 ref2.2 reactive 3、ref和reactive定义数组对比3.1 ref定义数组3.1 reactive定义数组 4、ref 和reactive的区别 1、前言 ref和reactive是Vue3中用来实现数据响应式的API,一般情况下,ref定义基本数据类型…...
QML与C++的交互操作
QML旨在通过C 代码轻松扩展。Qt QML模块中的类使QML对象能够从C 加载和操作,QML引擎与Qt元对象系统集成的本质使得C 功能可以直接从QML调用。这允许开发混合应用程序,这些应用程序是通过混合使用QML,JavaScript和C 代码实现的。除了从QML访问…...
Java_理解方法调用
理解方法调用 首先什么是隐式参数 --->隐式参数是调用该方法的对象本身。 接下来方法的名称和参数列表被称为方法的签名(signature)。在Java中,方法的签名由方法的名称和参数列表组成,用于唯一标识一个方法。返回类型不是签名的…...
九江网站建设优化公司/武汉seo优化顾问
ubuntu12.04 Grub启动项 1、异常开关机导致需要键盘选择启动项,如下图:此时需要用键盘,按下”Enter“键进入系统,如此操作很是烦人啊。。2、彻底解决这个问题的方法:(A)于是有效的方法是修改/etc/grub.d/00_head文件中…...
网站建设带宽多少合适/站长权重
.net下的富文本编辑器FCKeditor的配置方法(图)原创 FCKeditor是一款开源的富文本编辑器,几乎支持所有流行的Web开发语言,版本稳定,用户多,可配置性好。 以前做Java和php的时候就一直用FCKeditorÿ…...
dw做企业网站/无锡哪里有做网站的
为什么80%的码农都做不了架构师?>>> 为了实现Lua和其他语言之间的通信,Lua虚拟机为C/C提供了两个特性: 一,Lua_State状态机 lua_State主要是管理一个lua虚拟机的执行环境, 一个lua虚拟机可以有多个执行环境。Lua虚拟机…...
网站建设 培训班 成都/百度搜索app免费下载
我们在写Pattern的时候,有时会碰到需要特殊处理的符号。例如大小括号{}里面又包含了{},由于正在表达式是会将{}括号中的内容进行数值解析的。因此我们需要将括号作为字符串输出(注意:不是转义,不是转义,不是…...
维护一个网站要多少钱/安新seo优化排名网站
php修改文件内容的方法:首先通过file_put_contents函数写入文件;然后使fwrite配合fopen进行写入并修改的操作;最后通过file_exists等函数检测文件属性即可。file_put_contents写入文件我们先来学习第一种写入文件的方式:int file_…...
学做分类网站/如何制作一个自己的网站
Hello,大家好,今天给大家继续讲解排序系列。可能有细心的"鸟友"会问,你不是讲解排序吗?怎么今天的主题是一个查找方法咧? 不错,因为考虑到在实际项目中,排序和查找经常是两个好基友,二…...