定义
golang用来做 monkey patching 的测试库。
monkey patch :在运行时,动态修改一些变量/函数/方法/模块 的行为的能力。
对于有些三方的库,我们没有权限去调整代码逻辑,而这又会对我们测试带来影响,所以,我们通过【运行时替换】的方法来改掉这些实体的行为。
导包
import "github.com/agiledragon/gomonkey/v2"
使用注意事项
- gomonkey库只支持Arch架构,不能够在x86/amd上运行使用。
- 测试时需要关闭内联优化
go test -gcflags=all=-l
因为内联消除了调用目标函数时的跳转操作,使得go monkey填充在目标函数入口处的指令无法执行,因而也无法实现函数体的运行时替换,使go monkey失效。
使用示例
函数打桩
func ApplyFunc(target, double interface{}) *Patches
参数:target 目标函数,double替代函数
1.将clean函数用匿名函数代替
func clean() bool {println("do clean()")return true
}
func TestMonkey(t *testing.T) {println("monkey test")patchers := gomonkey.ApplyFunc(clean, func() bool {return false})defer patchers.Reset() //重置桩if clean() == true {t.Fatal("true")} else {t.Fatal("false") //最后运行了这一行,clean函数被替代}
- time.Now永远返回固定时间
func TestMonkey(t *testing.T) {println("monkey test")now := time.Now()gomonkey.ApplyFunc(time.Now, func() time.Time {return now})defer patchers.Reset()fmt.Println(time.Now())time.Sleep(time.Second * 3)fmt.Println(time.Now()) //这里与上面的结果相同}
方法打桩
func ApplyMethod(target reflect.Type, methodName string, double interface{}) *Patches
参数:
target:目标类型,根据reflect.TypeOf()获得。
methodName:方法名
double:替代函数,替代函数的第一个参数需要为对象类型或对象的指针
type A intfunc (a A) Print1(n int) {println(n)
}
func TestMonkey(t *testing.T) {var g_A Apatches := gomonkey.ApplyMethod(reflect.TypeOf(g_A), "Print1", func(a A, n int) {println("hello world")})defer patches.Reset()g_A.Print1(3) //如果没有被替代会打印3,实际上打印了helloworldt.Fatal("end") //不出错的话,println不会显示}
全局变量打桩
var c = 3func TestMonkey(t *testing.T) {patches :=gomonkey.ApplyGlobalVar(&c, 4)defer patches.Reset()println(c)//输出4t.Fatal("end")
}
参考:https://juejin.cn/post/7133520098123317256