github.com/bytedance/mockey@v1.2.10/README_cn.md (about) 1 # Mockey 2 3 [English](README.md) | 中文 4 5 Mockey 是一款简单易用的 Golang 打桩工具库,能够快速方便地进行函数、变量的 mock,目前在字节跳动各业务的单元测试编写中应用较为广泛,其底层是通过运行时改写函数指令实现的猴子补丁(Monkey Patch) 6 7 > 1. 编译时需要**禁用内联和编译优化**,否则可能会 mock 失败或者报错,详见下面的 [FAQ](#FAQ) 章节 8 > 2. 实际编写单测的过程中,建议结合 [Convey](https://github.com/smartystreets/goconvey) 库一起使用 9 10 ## 安装 11 ``` 12 go get github.com/bytedance/mockey@latest 13 ``` 14 15 ## 快速上手 16 ```go 17 import ( 18 "fmt" 19 "testing" 20 21 . "github.com/bytedance/mockey" 22 . "github.com/smartystreets/goconvey/convey" 23 ) 24 25 func Foo(in string) string { 26 return in 27 } 28 29 type A struct{} 30 31 func (a A) Foo(in string) string { return in } 32 33 var Bar = 0 34 35 func TestMockXXX(t *testing.T) { 36 PatchConvey("TestMockXXX", t, func() { 37 Mock(Foo).Return("c").Build() // mock函数 38 Mock(A.Foo).Return("c").Build() // mock方法 39 MockValue(&Bar).To(1) // mock变量 40 41 So(Foo("a"), ShouldEqual, "c") // 断言`Foo`成功mock 42 So(new(A).Foo("b"), ShouldEqual, "c") // 断言`A.Foo`成功mock 43 So(Bar, ShouldEqual, 1) // 断言`Bar`成功mock 44 }) 45 // `PatchConvey`外自动释放mock 46 fmt.Println(Foo("a")) // a 47 fmt.Println(new(A).Foo("b")) // b 48 fmt.Println(Bar) // 0 49 } 50 ``` 51 ## 功能概览 52 - mock 函数和方法 53 - 基础功能 54 - 普通/可变参数函数 55 - 普通/可变参数方法 56 - 嵌套结构体方法 57 - 私有类型的导出方法(不同包下) 58 - 高级功能 59 - mock 后执行原函数 60 - goroutine 条件过滤 61 - 增量改变 mock 行为 62 - 获取原函数执行次数 63 - 获取 mock 函数执行次数 64 - mock 变量 65 - 普通变量 66 - 函数变量 67 ## 兼容性 68 ### 平台支持 69 - Mac OS(Darwin) 70 - Linux 71 - Windows 72 ### 架构支持 73 - AMD64 74 - ARM64 75 ### 版本支持 76 - Go 1.13+ 77 78 ## 开源许可 79 80 Mockey 基于[Apache License 2.0](https://github.com/bytedance/mockey/blob/main/LICENSE-APACHE) 许可证,其依赖的三方组件的开源许可见 [Licenses](https://github.com/bytedance/mockey/blob/main/licenses) 81 82 ## FAQ 83 84 ### 如何禁用内联和编译优化? 85 1. 命令行:`go test -gcflags="all=-l -N" -v ./...` 86 2. Goland:在 **运行/调试配置 > Go工具实参** 对话框中填写 `-gcflags="all=-l -N"` 87 88 ### Mock 函数后仍走入了原函数? 89 1. 未禁用内联或者编译优化:可以尝试使用 debug 模式,如果能跑过则说明是该问题,请转到 FAQ [相关章节](#如何禁用内联和编译优化) 90 2. 未调用`Build()`方法:mock 函数时漏写了`.Build()`,导致没有任何实际效果产生 91 3. 目标函数不完全匹配: 92 ```go 93 func TestXXX(t *testing.T) { 94 Mock((*A).Foo).Return("c").Build() 95 fmt.Println(A{}.Foo("a")) // 走入原函数,目标函数应该是A.Foo 96 97 a := A{} 98 Mock(a.Foo).Return("c").Build() 99 fmt.Println(a.Foo("a")) // 走入原函数,目标函数应该是A.Foo或者使用工具函数GetMethod从a中获取 100 } 101 ``` 102 4. 目标函数在其他协程里执行: 103 ```go 104 func TestXXX(t *testing.T) { 105 PatchConvey("TestXXX", t, func() { 106 Mock(Foo).Return("c").Build() 107 go Foo("a") // 执行Foo的时机不定 108 }) 109 // 主协程走到这里时相关mock已经被PatchConvey释放,如果Foo先于此执行则mock成功,否则失败 110 fmt.Println("over") 111 time.Sleep(time.Second) 112 } 113 ``` 114 115 ### 报错 "function is too short to patch"? 116 1. 未禁用内联或者编译优化:可以尝试使用 debug 模式,如果能跑过则说明是该问题,请转到 FAQ [相关章节](#如何禁用内联和编译优化) 117 2. 函数确实太短:指目标函数小于一行,导致编译后机器码太短,一般两行及以上不会有这个问题 118 3. 重复 mock 同一个函数:在最小单位的`PatchConvey`中重复 mock 同一个函数,如果确实有这种需求可以尝试获取`Mocker`后重新 mock 119 4. 其他工具 mock 了该函数:例如已经使用 [monkey](https://github.com/bouk/monkey) 等工具 mock 了该函数