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)}
}

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

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

相关文章

UEFI学习笔记(十):系统表与ACPI表的遍历

一、概述 在 UEFI 系统表中,有几个关键的表用于提供系统信息、服务和硬件抽象。这些表可以通过 EFI_SYSTEM_TABLE 访问,常见的 UEFI 系统表如下: 1、EFI_SYSTEM_TABLE (系统表) EFI_SYSTEM_TABLE 是一个指针,包含多个服务和系统…

docker-compose无法切换用户

问题描述 jupyter:image: flink:1.19-pyprivileged: trueuser: rootports:- "9999:8888"volumes:- /data/docker_data/jupyter:/workcommand: sh -c "cd / && jupyter notebook --ip 0.0.0.0 --port 8888 --allow-root --NotebookApp.passwordsha1:658…

『网络游戏』动态界面制作创建角色UI【02】

将上一章的登录界面隐藏 创建空物体重命名为CreateWnd 自适应铺满父物体 创建image重命名为bg并铺满 将以下资源图片放进Art文件夹 设置为精灵模式 填充背景 创建介绍Image面板与角色按钮 制作将3D模型动态防止UI界面上 首先创建RawImage 创建RenderTextures文件夹 创建Render…

数字王国里的虚拟人――技术、商业与法律解读

💂 个人网站:【 摸鱼游戏】【神级代码资源网站】【海拥导航】🤟 找工作,来万码优才:👉 #小程序://万码优才/HDQZJEQiCJb9cFi💅 想寻找共同学习交流,摸鱼划水的小伙伴,请点击【全栈技…

DS1302时钟模块(STM32)

目录 一、介绍 二、模块原理 1.原理图 2.引脚描述 3.工作原理:读/写时序 4.寄存器地址/定义 三、程序设计 main.c文件 ds1302.h文件 ds1302.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 DS1302是一款由达拉斯半导体(Dallas Semic…

第三方软件测评机构简析:软件安全测试报告的内容和作用

随着数字化时代的到来,软件的安全性显得尤为重要。尤其在信息安全事件频发的今天,软件安全测试报告成为企业和开发者关注的焦点。软件安全测试报告是评估软件系统安全性的一种综合性文档,通常在软件开发生命周期中进行安全性测试后生成。 软…

windows C++-创建图像处理的异步消息(二)

创建图像处理网络 此部分介绍如何创建对给定目录中的每个 JPEG (.jpg) 图像执行图像处理的异步消息块网络。 网络执行以下图像处理操作: 对于 Tom 创作的任何图像,转换为灰度。 对于任何以红色作为主色的图像,移除绿色和蓝色分量&#xff0…

嵌入式项目:STM32平衡车详解 (基础知识篇) (基于STM32F103C8T6)

前言: 本文是基于B站草履虫编写的平衡车相关内容,包括模块和基础知识,结合代码进行讲解,将知识进行汇总 (由于本篇内容较长,请结合目录使用) 注:基于开源精神,本文仅供学习参考 目…

Java—逻辑控制与输入输出

各位看官:如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论,感谢您的支持!!! 一.顺序结构: 我每天起床,躺在床上玩手机,然后吃中午饭,睡…

PIFA天线工作原理:【图文讲解】

1:什么是PIFA天线 PIFA ( Planar Inverted F-shaped Antenna)天线即平面倒F形天线,因为整个天线的形状像个倒写的英文字母F而得名 2:PIFA天线的应用 PIFA常见于手机天线设计,占手机内置天线的60%-80% 3:PIFA天线结构…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-09

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-09 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-09目录1. Can LLMs plan paths with extra hints from solvers?摘要创新点算法模型实验效果重要数据与结论 推荐阅读指数 2. Sc…

SQL第14课挑战题

1. 将两个select语句结合起来,以便从OrderItems表中检索产品ID(prod_id)和quantity。其中,一个select语句过滤数量为100的行,另一个select语句过滤ID以BNBG开头的产品。按产品ID对结果进行排序。 2. 重新第一题,仅使用单个select语…

【原创】可用于 Android Studio 的翻译插件

在不少讲解Android 开发的老师视频中会出现一个运行在Android Studio 上的翻译插件,感觉挺实用的。 接下来,我们把它安装在我们的Android Studio 上。 设置 点击右上角齿轮按钮,选择Settings 安装 翻译插件 输入Tanslation,选…

[简单实践]Noisy Print - 自制基于加性噪声模型的简易降噪器

NoisyPrint 最近在学习的过程中,突然想起一个在Adobe Audition中用过的功能。 为什么会想到这个功能呢,因为在我使用DeepFilter的过程中,我发现对于一些低信噪比的信号来说,DeepFilter很容易出现过拟合现象,导致音源…

低质量数据的多模态融合方法

目录 多模态融合 低质量多模态融合的核心挑战 噪声多模态数据学习 缺失模态插补 平衡多模态融合 动态多模态融合 启发式动态融合 基于注意力的动态融合 不确定性感知动态融合 论文 多模态融合 多模态融合侧重于整合多种模态的信息,以实现更准确的预测,在自动驾驶、…

08_OpenCV文字图片绘制

import cv2 import numpy as npimg cv2.imread(image0.jpg,1) font cv2.FONT_HERSHEY_SIMPLEXcv2.rectangle(img,(500,400),(200,100),(0,255,0),20) # 1 dst 2 文字内容 3 坐标 4 5 字体大小 6 color 7 粗细 8 line type cv2.putText(img,flower,(200,50),font,1,(0,0,250)…

c#-出现类型初始值设定项引发异常的解决方案

当出现该问题时,通常摸不着头脑,无法定位到该问题所在行。 我们可以找到应发异常的类,例如我上面类为YY_Model.DefaultConfig。 打开这个类文件,加一个断点,一行行运行,到哪里突然跳出该文件,则…

(计算机毕设)基于Vue和Spring Boot的宠物救助网站设计与实现

博主可接毕设!!! 毕业设计(论文) 基于Vue和Spring Boot的宠物救助网站设计与实现 摘 要 随着中国互联网的迅猛发展,传统宠物救助领域面临着信息管理繁琐、辐射范围有限、信息传播受限、丢失宠物找回几率较…

机器学习框架(含实例说明)

机器学习框架是用于开发和部署机器学习模型的软件库和工具集。它们提供了一系列的算法、工具和基础设施,帮助开发者更高效地构建、训练和部署机器学习模型。以下是一些主要的机器学习框架及其详细介绍: 1. TensorFlow TensorFlow 是由Google开发的开源…

卫瓴科技,驶向「协同CRM」深水区

在卫瓴协同CRM的产品之上,能看到的不单纯是产品本身,即“提高转化率”这个单纯的指标,而更多的是在产品之中蕴含的“现代企业营销建设”的科学理念和认知。以此为基础,企业可以构建真正有价值且能长期驱动的品牌营销模型。 作者…