尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
多次调用,顺序返回不同结果
gomonkey.ApplyMethodSeq()高频实用方法处理「结构体方法被多次调用需要返回不同结果」的核心方法完美解决方法第 1 次调用返回 A、第 2 次返回 B、第 N 次返回默认值 / 报错 这类高频业务场景。这个也和上面2和3一样支持两种写法函数和结构体方法写法类似这里就只写一个示例了参数示例// 存储单次调用的返回值集合type Params []interface{}type OutputCell struct {Values Params // 本次要返回的参数个数/类型必须和原方法返回值完全一致Times int // 生效次数-1永久生效匹配后后续调用全用这个0生效指定次数}// 第一个参数要打桩的方法所属的类型通过 reflect.TypeOf(实例) 获取区分值接收者 / 指针接收者// 第二个参数要打桩的方法名字符串格式、大小写敏感必须和原方法名完全一致// 第三个参数打桩方法返回值切片入参和出参要保持和被打桩方法保持一致func (this *Patches) ApplyMethodSeq(target interface{}, methodName string, outputs []OutputCell) *Patches {m, ok : castRType(target).MethodByName(methodName)if !ok {panic(retrieve method by name failed)}d : getDoubleFunc(m.Type, outputs)return this.ApplyCore(m.Func, d)}product.gopackage method_demoimport fmt// 1. 定义业务结构体和待打桩的方法 type Product struct {Id intName stringStock int}// 结构体公有方法首字母大写库存查询返回【库存数量、错误信息】func (p *Product) GetStock() (int, error) {// 真实业务逻辑查询数据库/缓存获取库存return p.Stock, nil}// 2. 业务逻辑连续调用3次GetStock方法 // 模拟业务中多次调用结构体方法的场景func QueryStockMultiTimes(p *Product) {// 第1次调用stock1, err1 : p.GetStock()fmt.Printf(第1次查询库存: %d, err: %v\n, stock1, err1)// 第2次调用stock2, err2 : p.GetStock()fmt.Printf(第2次查询库存: %d, err: %v\n, stock2, err2)// 第3次调用stock3, err3 : p.GetStock()fmt.Printf(第3次查询库存: %d, err: %v\n, stock3, err3)}product_test.gopackage method_demoimport (errorsgithub.com/agiledragon/gomonkey/v2testing)func TestProduct(t *testing.T) {// 1. 创建patches实例必须写defer Reset()保证打桩还原无残留patches : gomonkey.NewPatches()defer patches.Reset()// 2. 初始化结构体实例prod : Product{Id: 1, Name: 苹果手机, Stock: 200}// 3. 核心定义序列打桩规则stockSeq : []gomonkey.OutputCell{{Values: gomonkey.Params{100, nil}, Times: 1}, // 规则1第1次调用返回100nil{Values: gomonkey.Params{0, nil}, Times: 1}, // 规则2第2次调用返回0nil{Values: gomonkey.Params{0, errors.New(库存不足无法下单)}, Times: 1}, // 规则3永久生效-1这个参数会导致严重bug避免使用}// 4. 执行方法序列打桩patches.ApplyMethodSeq(prod, GetStock, stockSeq)// 5. 执行业务逻辑触发多次调用QueryStockMultiTimes(prod)}命令行执行命令go test -run ^TestProduct$ -cover -gcflagsall-l -covermodeatomic结果PS D:\wyl\workspace\go\tracer\logic\method_demo go test -run ^TestProduct$ -cover -gcflagsall-l -covermodeatomic第1次查询库存: 100, err: nil第2次查询库存: 0, err: nil第3次查询库存: 0, err: 库存不足无法下单PASScoverage: 54.5% of statementsok tracer/logic/method_demo 0.330s5结构体私有方法打桩方法gomonkey.ApplyPrivateMethod()私有方法打桩方案方案一【最优推荐零侵入、Go 官方标准】测试文件和业务文件放在同一个包下首选无任何副作用方案二【妥协方案少量侵入】把「需要 mock 的私有方法」改为包级私有函数适合特殊场景方案三【不推荐侵入性大】把私有方法改为公有方法万不得已才用ApplyPrivateMethod和ApplyMethod打私有方法区别功能上完全一致同包下都能正常打桩、正常 mock 逻辑。唯一的区别是ApplyPrivateMethod语义精准一看就知道是打「私有方法」符合官方设计ApplyMethod语义模糊它的设计初衷是打「公有方法」打私有方法只是兼容生效。这个也和上面2和3一样支持两种写法函数和结构体方法写法类似这里就只写一个示例了参数示例// 第一个参数要打桩的方法所属的类型通过 reflect.TypeOf(实例) 获取区分值接收者 / 指针接收者// 第二个参数要打桩的方法名字符串格式、大小写敏感必须和原方法名完全一致// 第三个参数打桩方法入参和出参要保持和被打桩方法保持一致func (this *Patches) ApplyPrivateMethod(target interface{}, methodName string, double interface{}) *Patches {m, ok : creflect.MethodByName(castRType(target), methodName)if !ok {panic(retrieve method by name failed)}d : reflect.ValueOf(double)return this.ApplyCoreOnlyForPrivateMethod(m, d)}student.gopackage private_demotype Student struct{}// 公有方法对外暴露func (s Student) Study(course string) bool {// 内部调用了私有方法if s.checkCourse(course) { // 私有方法首字母小写s.recordLog(course) // 私有方法return true}return false}// 私有方法内部逻辑func (s Student) checkCourse(course string) bool {return course ! }func (s Student) recordLog(course string) {}student_test.gopackage private_demoimport (github.com/agiledragon/gomonkey/v2testing)// TODO: TestStudy有问题暂时不确定是因为不支持这种写法还是代码有问题func TestStudy(t *testing.T) {s : Student{}patches : gomonkey.NewPatches()defer patches.Reset()// ✅ 可以直接用gomonkey打桩【私有方法】checkCourse零权限问题patches.ApplyMethod(Student{}, checkCourse, func(_ *Student, course string) bool {return true // mock私有方法返回true})res : s.Study(math)if !res {t.Error(测试失败)}}// 测试代码指针接收者的私有方法打桩func TestStudyPrivate(t *testing.T) {s : Student{}patches : gomonkey.NewPatches()defer patches.Reset()patches.ApplyPrivateMethod((*Student)(nil), // ✅ 指针接收者传 (*结构体)(nil)checkCourse, // 私有方法名不变func(_ *Student, course string) bool { // ✅ 桩函数接收者是指针类型return true},)res : s.Study(math)if !res {t.Error(测试失败)}
RELATED

相关推荐

Python上下文管理器:with语句与__enter__/__exit__完全指南

Python上下文管理器:with语句与__enter__/__exit__完全指南

在Python编程中,上下文管理器(Context Manager)是一个强大而优雅的特性。它通过with语句实现了资源的自动获取和释放,让代码更加简洁、可读性更强,同时有效避免了资源泄漏问题。本文将深入探讨上下文管理器的工作原理、…

📅 2026/9/12 2:57:49
SetDPI:3步掌握Windows命令行DPI调整的终极方案

SetDPI:3步掌握Windows命令行DPI调整的终极方案

SetDPI:3步掌握Windows命令行DPI调整的终极方案 【免费下载链接】SetDPI 项目地址: https://gitcode.com/gh_mirrors/se/SetDPI 在Windows多显示器和高分辨率屏幕环境中,精准的DPI缩放设置直接影响工作效率和视觉体验。SetDPI作为一款专业的Wind…

📅 2026/9/16 8:49:59
Win11Debloat:3分钟免费优化Windows系统,让电脑重获新生

Win11Debloat:3分钟免费优化Windows系统,让电脑重获新生

Win11Debloat:3分钟免费优化Windows系统,让电脑重获新生 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to dec…

📅 2026/9/30 2:05:39
MORE NEWS

更多资讯

📰

嵌入式固件烧录与OTA升级实战:从编译到远程更新的完整链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

幼儿园守时习惯培养有必要吗?深度解析幼儿守时教育的核心价值与培养逻辑

幼儿园守时习惯培养有必要吗?深度解析幼儿守时教育的核心价值与培养逻辑“幼儿园时期培养孩子守时习惯,是幼儿自律教育的基石,直接决定孩子幼小衔接的适配能力。”不少家长存在育儿误区,认为幼儿年龄小,无需刻意约束时…

📰

CCNP ENCOR实战:PDF配置手册的ENSP转化与VLAN/Trunk排错指南

简介:本资源是一份面向网络工程师与CCNP备考者的进阶学习笔记,系统梳理思科CCNP认证核心内容,聚焦企业级园区网设计、部署与排错能力提升。资料基于主流培训机构内部PPT整理而成,涵盖交换(VLAN/Trunk/VTP、STP/PVST/RS…

📰

海誓山盟景区情侣浪漫景点推荐 用户力荐

三亚凤凰岭海誓山盟景区是集城市山顶生态观光、爱情主题文旅综合服务为一体的文旅目的地,可为赴三亚度假情侣、求婚新人、新婚旅拍人群等提供索道观光、观景打卡、仪式场地搭建等一体化文旅服务。作为三亚吉阳区核心山地文旅项目,三亚凤凰岭文化旅游有限…

📰

Linux部署TModLoader服务器:原理、避坑与systemd实战

1. 为什么必须用Linux跑TModLoader服务器——不是“能用”,而是“非它不可” 你可能刚在Windows上用TModLoader开过单机,也试过点几下“Host”按钮拉起一个局域网房间。但当朋友发来消息:“兄弟,今晚八点上线打Boss,记…

📰

改进遗传算法优化神经网络结构与超参

简介:本资源是一份面向人工智能与智能优化算法研究者的学术型技术文档,聚焦于解决神经网络训练中易陷局部最优、收敛缓慢等核心痛点,特别适用于高校研究生、算法工程师及互联网领域AI模型优化实践者。文档系统阐述了实数编码策略、改进型适应…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬