goland单元测试

一、单元测试的概念


1.1 什么是单元测试,有什么用?

单元测试是针对于函数的测试,用来保证该函数的逻辑正确性。

1.2 单元测试的要求?


1. 单元测试在正式上线之前应该全部自动执行,并且需要保证全部通过
2. 单元测试需要构建 【输入】 和 【预期输出】的case,case需要靠人工构建,涵盖各种边界情况
3. 单元测试需要测试到代码的每一个逻辑分支
4. 单元测试关注的是代码逻辑是否正确,无需关注网络调用、数据查询等,对于此部分代码可以mock掉
5. 单元测试行覆盖率要达到70%,函数覆盖率要达到100%(controller层除外)

1.3 单元测试的常见误区


1. 单元测试行覆盖率100%只能保证写的测试用例走过了所有的代码,但不能保证代码逻辑完全无误

1.4 gomock工具-gomonkey


官方文档 :https://github.com/agiledragon/gomonkey
使用教程:https://cloud.tencent.com/developer/article/1872029
https://www.ddhigh.com/2021/09/18/gomonkey-private-method-stub/ 解决了无法打桩私有方法的问题

二、单元测试实战

func GetFinalStatus(productName string) (status string, r ocommon.ResultInfo) {daoLockPtr := dao.CreateProductLockInfoPtr()query := oquery.NewQueryStructOfTable()var allLockList []dao.ProductLockInfoquery.AddConditonsByOperator("ProductName", oquery.OP_EQUAL, productName)r = daoLockPtr.SearchByQuery(&allLockList, query)if !r.IsOk() {return}// 如果产品线没有查到锁记录,则改产品线锁状态为【未锁定】if len(allLockList) == 0 {status = LOCK_STATUS_UNLOCKreturn}// 遍历所有的锁信息for _, lockItem := range allLockList {// 一旦发现硬锁定,则立即返回产品线锁状态为【硬锁定】if lockItem.LockStatus == LOCK_STATUS_HARDLOCK {status = LOCK_STATUS_HARDLOCKreturn}}// 遍历完也不存在硬锁定,那就一定是【软锁定】status = LOCK_STATUS_SOFTLOCKreturn
}
快速生成单元测试代码

编写测试用例
参考1.2 中的第三点,我们需要涵盖到每一个分支,所以该单元测试至少要有下面三个测试用例

单元测试用例用例一:测试软锁定用例二:测试硬锁定用例三:测试未锁定
输入SIODSIODSIOD
输出软锁定        硬锁定未锁定

mock数据并完成测试代码
参数1.2 中的第四点,该方法的单元测试关注的是代码逻辑是否正确,对于数据的来源不关注,再加上1.2 中的第一点,单元测试需要在每次提交代码之前,全部执行通过
所以我们需要mock掉 daoLockPtr.SearchByQuery 方法,并且将allLockList 变量用mock数据替代
如果不mock掉daoLockPtr.SearchByQuery,而是每次都去从数据库中查询,不可能同时通过上述三个测试用例
此时就用到了上面提到的测试工具,对daoLockPtr.SearchByQuery(&allLockList, query) 方法进行打桩 并mock掉 allLockList数据

具体实现如下方代码
func TestGetFinalStatus(t *testing.T) {type args struct {productName string}tests := []struct {name       stringargs       argswantStatus stringwantR      ocommon.ResultInfomockData   []dao.LockInfo // 此变量存储每一个测试用例的mock数据}{// TODO: Add test cases.{name:       "未锁定",args:       args{productName: "SIOD"},wantStatus: "unLock",wantR:      ocommon.ResultInfo{ErrNo: 0},mockData: nil, // 对于未锁定,mockData就是nil},{name:       "软锁定",args:       args{productName: "SIOD"},wantStatus: "softLock",wantR:      ocommon.ResultInfo{ErrNo: 0},mockData:   []dao.LockInfo{dao.LockInfo{LockStatus: LOCK_STATUS_SOFTLOCK}},// 对于软锁定,mockData的一种情况就是一条锁的状态为 【软锁】},{name:       "硬锁定",args:       args{productName: "SIOD"},wantStatus: "hardLock",wantR:      ocommon.ResultInfo{ErrNo: 0},mockData:   []dao.LockInfo{dao.LockInfo{LockStatus: LOCK_STATUS_HARDLOCK}},// 对于硬锁定,mockData的一种情况就是一条锁的状态为 【硬锁】},}for _, tt := range tests {// 使用 gomonkey 来 mock 方法patches := gomonkey.ApplyMethod(reflect.TypeOf(&dbBase.DbBase{}), "SearchByQuery", func(_ *dbBase.DbBase, allLockList interface{}, query *oquery.QueryStructOfTable) ocommon.ResultInfo {if data, ok := allLockList.(*[]dao.LockInfo); ok {*data = tt.mockData}return ocommon.ResultInfo{}})t.Run(tt.name, func(t *testing.T) {gotStatus, gotR := GetFinalStatus(tt.args.productName)if gotStatus != tt.wantStatus {t.Errorf("GetFinalStatus() gotStatus = %v, want %v", gotStatus, tt.wantStatus)}if !reflect.DeepEqual(gotR.ErrNo, tt.wantR.ErrNo) {t.Errorf("GetFinalStatus() gotR = %v, want %v", gotR.ErrNo, tt.wantR.ErrNo)}})// 每一个测试用例结束后,将mock的数据清除,不影响下一次mockpatches.Reset()}
}

查看单元测试覆盖率
我们在该方法所在的目录下面执行下面的命令,然后将单元测试的信息输出到目录下的c.out
执行单元测试

GOOS=darwin GOARCH=amd64 go test -cover -coverprofile=c.out -gcflags="all=-N -l" -run 'TestGetFinalStatus'


查看单元测试覆盖率,执行完之后,会自动打开一个html网页

go tool cover -html=c.out


从下图中,可以看出,我们在lock_info.go文件的单元测试覆盖率只有10.3%,我们需要把该文件中的其他方法根据项目实际情况补充单元测试


该方法中只有一行代码没有覆盖到,就是数据库查询错误,单元测试的目的是确保后续的代码逻辑正确,所以这一行代码可以不做测试

如何写出更加完备的单元测试?
上面代码可以看到对于该方法的覆盖已经达到每一个分支(数据库错误处理分支除外),但是其并不能保证其代码逻辑一定没有问题。
所以我们需要再补充几个单元测试用例,正如1.2 中的第二条一样,单元测试的难点就是需要人工去构思各种边界情况

{name:    "混合锁取最高级别",args:    args{productName: "SIOD"},wantStatus: "hardLock",wantR:   ocommon.ResultInfo{ErrNo: 0},mockData:  []dao.ProductLockInfo{{LockStatus: LOCK_STATUS_HARDLOCK}, {LockStatus: LOCK_STATUS_SOFTLOCK}}, // 此处的mockData 是一个硬锁,一个软锁
},
{name:    "多把相同状态的锁",args:    args{productName: "SIOD"},wantStatus: "hardLock",wantR:   ocommon.ResultInfo{ErrNo: 0},mockData:  []dao.ProductLockInfo{{LockStatus: LOCK_STATUS_HARDLOCK}, {LockStatus: LOCK_STATUS_HARDLOCK}}, // 此处的mockData 是一个硬锁,一个软锁
},


参考文章
https://www.liwenzhou.com/posts/Go/unit-test-0/#c-0-1-8
https://time.geekbang.org/column/article/10275?utm_campaign=geektime_search&utm_content=geektime_search&utm_medium=geektime_search&utm_source=geektime_search&utm_term=geektime_search

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475681.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

连接数据库:通过链和代理查询鲜花信息

目录 新的数据库查询范式 实战案例背景信息 创建数据库表 用 Chain 查询数据库 用 Agent 查询数据库 一直以来,在计算机编程和数据库管理领域,所有的操作都需要通过严格、专业且结构化的语法来完成。这就是结构化查询语言(SQL&#xff0…

【c++丨STL】stack和queue的使用及模拟实现

🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

aws上安装ssm-agent

aws-cloudwatch 连接机器 下载ssm-agent aws-ec2 安装ssm-agent aws-linux安装ssm-agent 使用 SSM 代理查找 AMI 预装 先运行:systemctl status amazon-ssm-agent 查看sshm-agent的状态。 然后安装提示,执行 systemctl start amazon-ssm-agent 启动即…

百度世界2024:智能体引领AI应用新纪元

在近日盛大举行的百度世界2024大会上,百度创始人李彦宏以一场题为“文心一言”的精彩演讲,再次将全球科技界的目光聚焦于人工智能(AI)的无限可能。作为一名科技自媒体,我深感这场演讲不仅是对百度AI技术实力的一次全面…

纯血鸿蒙NEXT-组件导航 (Navigation)

Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(NavDestination的子组件…

C语言 | Leetcode C语言题解之第564题寻找最近的回文数

题目&#xff1a; 题解&#xff1a; #define MAX_STR_LEN 32 typedef unsigned long long ULL;void reverseStr(char * str) {int n strlen(str);for (int l 0, r n-1; l < r; l, r--) {char c str[l];str[l] str[r];str[r] c;} }ULL * getCandidates(const char * n…

docker学习笔记跟常用命令总结

Docker简介 Docker是一个用于构建运行传送应用程序的平台 镜像 将应用所需的函数库、依赖、配置等与应用一起打包得到的就是镜 镜像结构 镜像管理命令 命令说明docker pull拉取镜像docker push推送镜像docker images查看本地镜像docker rmi删除本地镜像docker image prune…

MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

MySQL中的InnoDB存储引擎支持四种事务隔离级别&#xff0c;这些级别定义了事务在并发环境中的行为和相互之间的可见性。以下是这四种隔离级别的名称以及它们之间的区别&#xff1a; 读未提交&#xff08;Read Uncommitted&#xff09; 特点&#xff1a;这是最低的隔离级别&…

【力扣热题100】[Java版] 刷题笔记-226. 翻转二叉树

题目:226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 解题思路 二叉树翻转&#xff0c;可以通过递归进行交换。 解题过程 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeN…

Android kotlin之配置kapt编译器插件

配置项目目录下的gradle/libs.versions.toml文件&#xff0c;添加kapt配置项&#xff1a; 在模块目录下build.gradle.kt中增加 plugins {alias(libs.plugins.android.application)alias(libs.plugins.jetbrains.kotlin.android)// 增加该行alias(libs.plugins.jetbrains.kotl…

【Linux学习】【Ubuntu入门】1-8 ubuntu下压缩与解压缩

1.Linux系统下常用的压缩格式 常用的压缩扩展名&#xff1a;.tar、.tar.bz2、.tar.gz 2.Windows下7ZIP软件安装 Linux系统下很多文件是.bz2&#xff0c;.gz结尾的压缩文件。 3.Linux系统下gzip压缩工具 gzip工具负责压缩和解压缩.gz格式的压缩包。 gzip对单个文件进行…

【Linux】【Shell】Shell 基础与变量

Shell 基础 Shell 基础查看可用的 Shell判断当前 Shell 类型 变量环境变量查看环境变量临时环境变量永久环境变量PATH 变量 自定义变量特殊赋值(双引号、单引号、反撇号) 预定义变量bashrc Shell 基础 Shell 是一个用 C 语言编写的程序&#xff0c;相当于是一个翻译&#xff0c…

自动语音识别(ASR)与文本转语音(TTS)技术的应用与发展

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

React可以做全栈开发吗

React可以做全栈开发吗? 答案是肯定的&#xff0c;而且还比较完美 React可以用于全栈开发&#xff0c;以下是具体的介绍&#xff1a; 前端部分 构建用户界面 React是一个用于构建用户界面的JavaScript库&#xff0c;它通过组件化的方式让开发者能够高效地创建交互式的UI。例…

折叠光腔衰荡高反射率测量技术的matlab模拟理论分析

折叠光腔衰荡高反射率测量技术的matlab模拟理论分析 1. 前言2. 光腔模型3. 光腔衰荡过程4. 衰荡时间与反射率的关系5. 测量步骤①. 光腔调节&#xff1a;②. 光腔衰荡测量&#xff1a;③. 计算衰荡时间常数&#xff1a;④. 反射率计算&#xff1a; 6. 实际应用中的调整7. 技术优…

爬取网易云音乐热歌榜:从入门到实战

爬取网易云音乐热歌榜&#xff1a;从入门到实战 前提声明 爬虫应遵守目标网站的robots.txt协议&#xff0c;尊重版权和用户隐私。本代码仅供学习和研究使用&#xff0c;不得用于商业用途。请确保在合法合规的前提下使用本代码。本代码所爬音乐为公开可选择的音乐 目录 引言…

C语言菜鸟入门·关键字·void的用法

目录 1. void关键字 1.1 对函数返回的限定 1.2 对函数参数的限定 1.3 用作指针类型 (void*) 2. 更多关键字 1. void关键字 在 C 语言中&#xff0c;void 是一个关键字&#xff0c;用于表示“无类型”或“没有值”。 void的作用&#xff1a; 对函数返回的限定对函数参…

PlncRNA-HDeep:使用基于两种编码风格的混合深度学习进行植物长非编码 RNA 预测

长链非编码 RNA &#xff08;lncRNAs&#xff09; 在调控生物活动中起着重要作用&#xff0c;其预测对探索生物过程具有重要意义。长短期记忆 &#xff08;LSTM&#xff09; 和卷积神经网络 &#xff08;CNN&#xff09; 可以自动从编码的 RNA 序列中提取和学习抽象信息&#x…

HTML5实现剪刀石头布小游戏(附源码)

文章目录 1.设计来源1.1 主界面1.2 皮肤风格1.2 游戏中界面 2.效果和源码源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/143798520 HTM…

【软件测试】自动化常用函数

文章目录 元素的定位cssSelectorxpath查找元素 操作测试对象点击/提交对象——click()模拟按键输入——sendKeys(“”)清除文本内容——clear()获取文本信息——getText()获取页面标题和 URL 窗口设置窗口大小切换窗口关闭窗口 等待强制等待隐式等待显式等待 浏览器导航 元素的…