定义
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 int
func (a A) Print1(n int) {
println(n)
}
func TestMonkey(t *testing.T) {
var g_A A
patches := gomonkey.ApplyMethod(reflect.TypeOf(g_A), "Print1", func(a A, n int) {
println("hello world")
})
defer patches.Reset()
g_A.Print1(3) //如果没有被替代会打印3,实际上打印了helloworld
t.Fatal("end") //不出错的话,println不会显示
}
全局变量打桩
var c = 3
func TestMonkey(t *testing.T) {
patches :=gomonkey.ApplyGlobalVar(&c, 4)
defer patches.Reset()
println(c)//输出4
t.Fatal("end")
}
参考:https://juejin.cn/post/7133520098123317256