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

Go基础学习11-测试工具gomock和monkey的使用

文章目录

  • 基础回顾
  • Mock
    • Mock是什么
    • 安装gomock
    • Mock使用
      • 1. 创建user.go源文件
      • 2. 使用mockgen生成对应的Mock文件
      • 3. 使用mockgen命令生成后在对应包mock下可以查看生成的mock文件
      • 4. 编写测试代码
      • 5. 运行代码并查看输出
  • Gomonkey
    • Gomonkey优势
    • 安装
    • 使用
      • 对函数进行monkey
      • 对结构体中方法进行monkey
      • 对全局变量进行monkey

基础回顾

测试:
在这里插入图片描述在这里插入图片描述
● 建立完善的回归测试,如果采用微服务,可以限制测试范围,只需要保证独立的微服务内部功能正常,因为微服务对外暴露的是接口。
● 为什么要将测试文件和源文件写到一个包中:便于测试包级别的示例,方法。

  • go test 命令是一个按照一定约定和组织的测试代码驱动测试,在包目录下 所有以_test.go结尾的文件都会被视为测试文件。并且 _test.go结尾的文件不会被go build 编译到可执行文件中。

Mock

Mock是什么

Mock是单元测试中常见的一种技术,就是在测试过程中,对于一些不容易构造或者获取的对象,创建一个Mock对象来模拟对象的行为,从而把测试与测试边界以外的对象隔离开。
优点:
团队并行工作
测试驱动开发 TDD (Test-Driven Development)
测试覆盖率
隔离系统
缺点

  • Mock不是万能的,使用Mock也存在着风险,需要根据项目实际情况和具体需要来确定是否选用Mock。
  • 测试过程中如果大量使用Mock,mock测试的场景失去了真实性,可能会导致在后续的系统性测试时才发现bug,使得缺陷发现的较晚,可能会造成后续修复成本更大

Mock广泛应用于接口类的方法的生成。 针对接口可以使用mock,针对不是接口的函数或者变量使用下面的monkey。

安装gomock

go get github.com/golang/mock/gomock
go get github.com/golang/mock/mockgen
go install github.com/golang/mock/mockgen@v1.6.0

安装完成后执行mockgen命令查看是否生效

Mock使用

1. 创建user.go源文件

// Package mock  ------------------------------------------------------------
// @file      : user.go
// @author    : WeiTao
// @contact   : 15537588047@163.com
// @time      : 2024/10/4 13:16
// ------------------------------------------------------------
package mockimport "context"type User struct {Mobile   stringPassword stringNickName string
}type UserServer struct {Db UserData
}func (us *UserServer) GetUserByMobile(ctx context.Context, mobile string) (User, error) {user, err := us.Db.GetUserByMobile(ctx, mobile)if err != nil {return User{}, err}if user.NickName == "TestUser" {user.NickName = "TestUserModified"}return user, nil
}type UserData interface {GetUserByMobile(ctx context.Context, mobile string) (User, error)
}

上述代码中的UserData是一个Interface{}类型,后面使用Mock生成的对象就是此接口对象,生成后可以将UserData接口中的方法GetUserByMoblie方法实现黑盒,从而无需关注具体实现细节,直接可以设置此函数对应的返回值。

2. 使用mockgen生成对应的Mock文件

mockgen使用:

// 源码模式mockgen -source 需要mock的文件名 -destination 生成的mock文件名 -package 生成mock文件的包名
// 参考示例:
mockgen -source user.go -destination=./mock/user_mock.go -package=mock

3. 使用mockgen命令生成后在对应包mock下可以查看生成的mock文件

// Code generated by MockGen. DO NOT EDIT.
// Source: user.go// Package mock is a generated GoMock package.
package mockimport (context "context"reflect "reflect"gomock "github.com/golang/mock/gomock"
)// MockUserData is a mock of UserData interface.
type MockUserData struct {ctrl     *gomock.Controllerrecorder *MockUserDataMockRecorder
}// MockUserDataMockRecorder is the mock recorder for MockUserData.
type MockUserDataMockRecorder struct {mock *MockUserData
}// NewMockUserData creates a new mock instance.
func NewMockUserData(ctrl *gomock.Controller) *MockUserData {mock := &MockUserData{ctrl: ctrl}mock.recorder = &MockUserDataMockRecorder{mock}return mock
}// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserData) EXPECT() *MockUserDataMockRecorder {return m.recorder
}// GetUserByMobile mocks base method.
func (m *MockUserData) GetUserByMobile(ctx context.Context, mobile string) (User, error) {m.ctrl.T.Helper()ret := m.ctrl.Call(m, "GetUserByMobile", ctx, mobile)ret0, _ := ret[0].(User)ret1, _ := ret[1].(error)return ret0, ret1
}// GetUserByMobile indicates an expected call of GetUserByMobile.
func (mr *MockUserDataMockRecorder) GetUserByMobile(ctx, mobile interface{}) *gomock.Call {mr.mock.ctrl.T.Helper()return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByMobile", reflect.TypeOf((*MockUserData)(nil).GetUserByMobile), ctx, mobile)
}

观察上述Mock文件可以看到实现了GetUserByMobile方法等。

4. 编写测试代码

// ------------------------------------------------------------
// package test
// @file      : user_test.go
// @author    : WeiTao
// @contact   : 15537588047@163.com
// @time      : 2024/10/4 13:23
// ------------------------------------------------------------
package mockimport ("context""github.com/golang/mock/gomock""testing"
)func TestGetUserByMobile(t *testing.T) {// mock准备工作ctl := gomock.NewController(t)defer ctl.Finish()userData := NewMockUserData(ctl)userData.EXPECT().GetUserByMobile(gomock.Any(), "15023076751").Return(User{Mobile:   "15023076751",Password: "123456",NickName: "TestUser",},nil,)// 实际调用过程userServer := UserServer{Db: userData,}user, err := userServer.GetUserByMobile(context.Background(), "15023076751")// 判断过程if err != nil {t.Error("GetUserByMobile error:", err)}if user.Mobile != "15023076751" || user.Password != "123456" || user.NickName != "TestUserModified" {t.Error("GetUserByMobile result is not expected.")}
}

5. 运行代码并查看输出

GOROOT=/usr/local/go #gosetup
GOPATH=/home/wt/Backend/go/goprojects #gosetup
/usr/local/go/bin/go test -c -o /home/wt/.cache/JetBrains/GoLand2024.2/tmp/GoLand/___TestGetUserByMobile_in_golearndetail_test_mock.test golearndetail/test/mock #gosetup
/usr/local/go/bin/go tool test2json -t /home/wt/.cache/JetBrains/GoLand2024.2/tmp/GoLand/___TestGetUserByMobile_in_golearndetail_test_mock.test -test.v=test2json -test.paniconexit0 -test.run ^\QTestGetUserByMobile\E$
=== RUN   TestGetUserByMobile
--- PASS: TestGetUserByMobile (0.00s)
PASSProcess finished with the exit code 0

Gomonkey

Gomonkey优势

上面使用mockgen生成对应的mock文件缺点非常明显,只能对于接口类的函数进行mock,然而实际项目并非所有函数都是接口类函数,大部分是内部使用的临时函数以及变量等,此时对这些函数以及变量无法使用mockgen生成对应的mock文件,此时可以使用另一个工具gomonkey
链接:https://github.com/agiledragon/gomonkey

安装

参考官网安装说明:

$ go get github.com/agiledragon/gomonkey/v2@v2.11.0

使用

对函数进行monkey

  1. 编写函数
package monkeyfunc networkCompute(a, b int) (int, error) {c := a + breturn c, nil
}func compute(a, b int) (int, error) {c, err := networkCompute(a, b)return c, err
}
  1. 编写测试用例
// 对函数进行mock
func Test_compute(t *testing.T) {patches := gomonkey.ApplyFunc(networkCompute, func(a, b int) (int, error) {return 8, nil})defer patches.Reset()sum, err := compute(1, 2)if err != nil {t.Error("Error occurred:", err)}fmt.Printf("sum : %d\n", sum)if sum != 8 {t.Error("Error occurred in sum:", err)}
}

在使用gomonkey运行测试用例的时候,直接run会报内联错误,解决方法有两个:

  • 在终端执行命令go test时加上参数:go test -gcflags=all=-l
  • 在Goland编辑器添加对应go运行变量:-gcflags=all=-l
  • 在这里插入图片描述
    加上 "all=-N -l"和”=all=-l"效果相同。
  1. 运行结果
/usr/local/go/bin/go tool test2json -t /home/wt/.cache/JetBrains/GoLand2024.2/tmp/GoLand/___7Test_compute_in_golearndetail_test_monkey.test -test.v=test2json -test.paniconexit0 -test.run ^\QTest_compute\E$
=== RUN   Test_compute
sum : 8
--- PASS: Test_compute (0.00s)
PASSProcess finished with the exit code 0

对结构体中方法进行monkey

  1. 编写代码
type Compute struct{}func (c *Compute) NetworkCompute(a, b int) (int, error) {sum := a + breturn sum, nil
}func (c *Compute) Compute(a, b int) (int, error) {sum, err := c.NetworkCompute(a, b)return sum, err
}
  1. 编写测试用例
// 对结构体中的方法进行mock
func Test_Compute_NetworkCompute(t *testing.T) {var compute *Computepatches := gomonkey.ApplyMethod(reflect.TypeOf(compute), "NetworkCompute", func(_ *Compute, a, b int) (int, error) {return 10, nil})defer patches.Reset()compute = &Compute{}sum, err := compute.Compute(3, 2)if err != nil {t.Error("Error occurred:", err)}fmt.Printf("sum : %d\n", sum)if sum != 10 {t.Error("Error occurred in sum:", err)}
}
  1. 运行结果
/usr/local/go/bin/go tool test2json -t /home/wt/.cache/JetBrains/GoLand2024.2/tmp/GoLand/___2Test_Compute_NetworkCompute_in_golearndetail_test_monkey.test -test.v=test2json -test.paniconexit0 -test.run ^\QTest_Compute_NetworkCompute\E$
=== RUN   Test_Compute_NetworkCompute
sum : 10
--- PASS: Test_Compute_NetworkCompute (0.00s)
PASSProcess finished with the exit code 0

对全局变量进行monkey

代码展示:

var num = 5// 对变量进行mock
func Test_GlobalVal(t *testing.T) {patches := gomonkey.ApplyGlobalVar(&num, 10)defer patches.Reset()if num != 10 {t.Error("Error occurred in num:mock failure", num)}
}

相关文章:

Go基础学习11-测试工具gomock和monkey的使用

文章目录 基础回顾MockMock是什么安装gomockMock使用1. 创建user.go源文件2. 使用mockgen生成对应的Mock文件3. 使用mockgen命令生成后在对应包mock下可以查看生成的mock文件4. 编写测试代码5. 运行代码并查看输出 GomonkeyGomonkey优势安装使用对函数进行monkey对结构体中方法…...

PHP基础教程

PHP基础教程 1. PHP简介 PHP是一种广泛使用的开源服务器端脚本语言,它特别适用于网页开发,并可嵌入到HTML中使用。 2. PHP环境搭建 Windows: 可以使用XAMPP或WAMP。Mac: 可以使用MAMP。Linux: 可以使用XAMPP或LAMP。 3. 第一个PHP程序 创建一个名为…...

Python或R时偏移算法实现

🎯要点 计算单变量或多变量时序距离,使用欧几里得、曼哈顿等函数量化不同时序差异。量化生成时序之间接近度相似性矩阵。使用高尔距离和堪培拉距离等相似度测量。实现最小方差匹配算法,绘制步进模式的图形表示。其他语言包算法实现。 &…...

华为云LTS日志上报至观测云最佳实践

华为云LTS简介 华为云云日志服务(Log Tank Service,简称 LTS),用于收集来自主机和云服务的日志数据,通过海量日志数据的分析与处理,可以将云服务和应用程序的可用性和性能最大化,为您提供实时、…...

Python--加载Hugging Face模型文件异常处理

尝试加载 Hugging Face 模型的配置文件时,无法从 https://huggingface.co 获取所需的 config.json 文件。这个错误通常是由于网络连接问题、访问受限或路径配置错误导致的。让我们一步步分析并解决这个问题。 可能原因及解决方案: 网络连接问题&#xf…...

补码加/减运算的具体示例

补码加法运算示例 示例:计算两个十进制数的和,35 18,假设使用8位二进制表示。 1、求原码: 35的原码:00100011 18的原码:00010010 2、求补码(对于正数,补码与原码相同&#xff0…...

macOS编译和运行prometheus2.54

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文详述了在macOS(M2芯片)上编译和运行prometheus2.54版本的过程,以及安装node_exporter和grafana并使用prometheus指标进行展示 本地…...

flume系列之:flume jmx页面导出flume、java进程等全部指标

flume系列之:flume jmx页面导出flume、java进程等全部指标 一、需求背景二、完整的jmx指标信息三、修改jmx指标导出规则四、启动jmx导出程序一、需求背景 目前jmx页面指标只导出了flume相关的指标,现在需要导出java相关的指标二、完整的jmx指标信息 主要有flume指标java进程指…...

(17)MATLAB使用伽马(gamma)分布生成Nakagami-m分布的方法1

文章目录 前言一、使用伽马分布生成Nakagami分布随机变量的方法一二、MATLAB仿真代码后续 前言 MATLAB在R2013a版本中引入Nakagami分布对象,可以用来生成Nakagami随机变量。但是在更早的MATLAB版本中,并没有可以直接生成 Nakagami分布的随机变量的内置的…...

NFT 是什么?

NFT 是什么? NFT,全称Non-Fungible Token,即“非同质化代币”,是一种基于区块链技术的独特数字资产。NFT的核心特性在于其唯一性、不可分割性和不可替代性,这使其与传统的加密货币(如比特币、以太坊等)形成了鲜明的对比。比特币等加密货币是同质化的,每个单位之间可以…...

mysql的学习

垂直连接union join是水平连接,UNION 是垂直连接,它是把两张表的结果集按列堆叠,行数增加了,但列数保持不变。 UNION 垂直连接的作用 在 MySQL 中,UNION 可以将两个具有相同列数且列数据类型兼容的查询结果合并在一…...

微服务之间的相互调用的几种常见实现方式对比

目录 微服务之间的相互调用的几种实现方式 一、HTTP HTTP/RESTful API调用工作原理 二、RPC 设计理念与实现方式 协议与传输层 RPC远程调用工作原理 应用场景与性能考量 特点 三、Feign 设计理念与实现方式 协议与传输层 Feign调用的基本流程 Feign调用的工作原理…...

FPGA时序分析和约束学习笔记-(1、FPGA基本原理)

FPGA时序分析和约束学习笔记-(1、FPGA基本原理) Field现场Programmable可编程Gate门Array阵列 1、FPGA基本资源组成 可编程逻辑功能块(logic elements ,缩写LE) 片内互联线(interconnect,缩写…...

华为仓颉语言入门(9):for-in表达式

for-in 表达式用于遍历序列,它会依次访问序列中的每个元素,直到遍历完成。它常用于处理列表、数组或其他集合类型,能够有效简化代码,减少重复劳动。其基本语法如下: for (循环变量 in 序列) {循环体 }在 for-in 表达式中,每次循环都会检查是否遍历了序列中的所有元素。如…...

Vue3中使用axios

Promise介绍 同步代码与异步代码 安装并引入axios npm install axios 此时package.json里面就多了axios依赖 引入axios 获取数据 Axios GET参数构成:axios.get(url,{config{},…{}…}) url: 字符串:目标服务器的地址,如 https://api.examp…...

国创——VR虚拟陪伴

VR虚拟陪伴 1.技术基础:利用VR技术创建虚拟人物,实现与用户的互动。 2.功能实现:在用户等待就诊或无聊时,可以启动VR虚拟陪伴功能,与虚拟人物进行聊天、唱歌等互动,缓解用户的紧张情绪。 3.创新点&#…...

【Android 源码分析】Activity生命周期之onPause

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…...

​IAR全面支持国科环宇AS32X系列RISC-V车规MCU

全球领先的嵌入式系统开发软件解决方案供应商IAR与北京国科环宇科技股份有限公司(以下简称”国科环宇”)联合宣布,最新版本IAR Embedded Workbench for RISC-V将全面支持国科环宇AS32X系列RISC-V MCU,双方将共同助力中国汽车行业开…...

Java题集(从入门到精通)04

此系列文章收录大量Java经典代码题(也可以算是leetcode刷题指南),希望可以与大家一起努力学好Java。3、2、1,请看! 目录 一、北京地铁计价程序 二、人名币兑换 三、各位数字之和 一、北京地铁计价程序 【问题描述…...

《西北师范大学学报 (自然科学版)》

《西北师范大学学报》(自然科学版) (CN 62-1087/N, ISSN 1001-988X)是甘肃省教育厅主管、西北师范大学主办的综合性自然科学学术期刊,1942年3月创刊,双月刊,逢单月15日出版。主要刊登全国高校和科研院所在数学、计算机与信息科学、物理学、化…...

Oracle SQL语句没有过滤条件,究竟是否会走索引??

答案是:可能走索引也可能不走索引,具体要看列的值可不可为null,Oracle不会为所有列的nullable属性都为Y的sql语句走索引。 例子: create table t as select * from dba_objects; CREATE INDEX ix_t_name ON t(object_id, objec…...

Java中参数传递:按值还是按引用?

目录 1. 按值传递 vs 按引用传递 1.1 基本数据类型:按值传递 1.2 对象引用:按引用传递 2. 拓展知识:理解 Java 的内存模型 2.1 栈内存的作用 2.2 堆内存的作用 2.3 参数传递的底层机制 3. 总结 在软件开发的世界里,Java 是…...

Linux忘记root用户密码怎么重设密码

直接说步骤: 1.重启客户机 2.在选择内核页面快速按e键,进入编辑模式 进入后应该是这个样子 在这里只能按上下键切换行 找到Linux16这里 3.按右方向键切换到行尾,也就是UTF-8处,在后面添加一个空格,然后加上这段话 …...

【Web】复现n00bzCTF2024 web题解(全)

目录 File Sharing Portal 方法一: 方法二: Focus-on-yourSELF Passwordless File Sharing Portal 附件的Dockerfile给了这么一段 # Add the cron job to the crontab RUN mkdir /etc/cron.custom RUN echo "*/5 * * * * root rm -rf /app…...

仿RabbitMQ实现消息队列客户端

文章目录 客⼾端模块实现订阅者模块信道管理模块异步⼯作线程实现连接管理模块生产者客户端消费者客户端 客⼾端模块实现 在RabbitMQ中,提供服务的是信道,因此在客⼾端的实现中,弱化了Client客⼾端的概念,也就是说在RabbitMQ中并…...

CSS | 面试题:你知道几种移动端适配方案?

目录 一、自适应和响应式 二、为什么要做移动端适配? 三、当前流行的几种适配方案 (1) 方案一:百分比设置(不推荐) (2) 方案二:rem 动态设置 font-size px 与 rem 的单位换算 手动换算 less/scss函数 webpac…...

【web安全】——XSS漏洞

1.XSS漏洞基础 1.1.漏洞成因 XSS(Cross-site scripting)被称为跨站脚本攻击,由于与层叠样式表的缩写一样,因此被缩写为XSS.XSS漏洞形成的原因是网站/程序对前端用户的输入过滤不严格,导致攻击者可以将恶意的is/html代码注入到网页中&#x…...

JAVA基础语法 Day11

一、Set集合 Set特点:无序(添加数据的顺序和获取出的数据顺序不一致),不重复,无索引 public class demo1 {public static void main(String[] args) {//1.创建一个集合//HashSet特点:无序,不重…...

知识图谱入门——7:阶段案例:使用 Protégé、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop 搭建知识图谱

在 Windows 环境中结合使用 Protg、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop,可以高效地实现从自然语言处理(NLP)到知识图谱构建的全过程。本案例将详细论述环境配置、步骤实现以及一些扩展和不足之处。 文章目录 1. 环境准备1.1 Neo4j…...

【AIGC】VoiceControl for ChatGPT指南:轻松开启ChatGPT语音对话模式

博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯安装VoiceControl for ChatGPT插件💯如何使用VoiceControl for ChatGPT进行语音输入VoiceControl for ChatGPT快捷键注意点 💯VoiceControl for C…...