当前位置: 首页 > news >正文

gomonkey调研文档和学习

文章目录

  • gomonkey调研文档和学习
    • gomonkey概述
    • examples
      • 1 为函数打桩
      • 2 函数打序列桩
      • 3、函数变量打桩
      • 5、全局变量打桩
      • 6、成员方法打桩
      • 7、成员方法打序列桩
      • 8、接口打桩
    • 总结

gomonkey调研文档和学习

gomonkey概述

学习地址
gomonkey 是 golang 的一款打桩框架,目标是让用户在单元测试中低成本的完成打桩,从而将精力聚焦于业务功能的开发。
特性列表:

  • 支持为一个函数打一个桩
  • 支持为一个成员方法打一个桩
  • 支持为一个接口打一个桩
  • 支持为一个全局变量打一个桩
  • 支持为一个函数变量打一个桩
  • 支持为一个函数打一个特定的桩序列
  • 支持为一个成员方法打一个特定的桩序列
  • 支持为一个函数变量打一个特定的桩序列
  • 支持为一个接口打一个特定的桩序列

examples

例子中所有的代码都在这:https://github.com/fishingfly/gomonkey_examples

1 为函数打桩

ApplyFunc 第一个参数是函数名,第二个参数是桩函数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport ("./fake""encoding/json". "github.com/agiledragon/gomonkey". "github.com/smartystreets/goconvey/convey""testing"
)var (outputExpect = "xxx-vethName100-yyy"
)func TestApplyFunc(t *testing.T) {Convey("TestApplyFunc", t, func() {Convey("one func for succ", func() {patches := ApplyFunc(fake.Exec, func(_ string, _ ...string) (string, error) {return outputExpect, nil})defer patches.Reset()output, err := fake.Exec("", "")So(err, ShouldEqual, nil)So(output, ShouldEqual, outputExpect)})Convey("one func for fail", func() {patches := ApplyFunc(fake.Exec, func(_ string, _ ...string) (string, error) {return "", fake.ErrActual})defer patches.Reset()output, err := fake.Exec("", "")So(err, ShouldEqual, fake.ErrActual)So(output, ShouldEqual, "")})Convey("two funcs", func() {patches := ApplyFunc(fake.Exec, func(_ string, _ ...string) (string, error) {return outputExpect, nil})defer patches.Reset()patches.ApplyFunc(fake.Belong, func(_ string, _ []string) bool {return true})output, err := fake.Exec("", "")So(err, ShouldEqual, nil)So(output, ShouldEqual, outputExpect)flag := fake.Belong("", nil)So(flag, ShouldBeTrue)})Convey("input and output param", func() {patches := ApplyFunc(json.Unmarshal, func(data []byte, v interface{}) error {if data == nil {panic("input param is nil!")}p := v.(*map[int]int)*p = make(map[int]int)(*p)[1] = 2(*p)[2] = 4return nil})defer patches.Reset()var m map[int]interr := json.Unmarshal([]byte("123"), &m)So(err, ShouldEqual, nil)So(m[1], ShouldEqual, 2)So(m[2], ShouldEqual, 4)})})
}

这边是对fake.exec函数打桩,模拟exec函数的输出。,fake.exec函数在fake目录下,可以来下我的代码库看下。
上面这种模拟函数输出有啥应用,从我实际使用的角度出发,我们看下面例子:
mytest.go

package mytestfunc AddOne(t int32) int32 {return t+1
}func MinusOne(t int32) int32 {return t-1
}func MultiAddOne(t int32) int32 {t = MinusOne(t)t = AddOne(t)t = AddOne(t)return t
}

测试类mytest_test.go

package mytestimport (. "github.com/agiledragon/gomonkey". "github.com/smartystreets/goconvey/convey""testing"
)func TestMultiAddOne(t *testing.T) {Convey("TestApplyFunc", t, func() {Convey("input and output param", func() {patches := ApplyFunc(AddOne, func(t1 int32) int32 {return 0})//对函数AddOne打桩defer patches.Reset()patches.ApplyFunc(MinusOne, func(t1 int32) int32 {return -1})//对函数MinusOne打桩result := MultiAddOne(10) //看好了我调用的是MultiAddOne函数,而MultiAddOne函数内部调用了AddOne和MinusOne。So(result, ShouldEqual, 0)})})
}

我模拟了AddOne和MinusOne函数的输出,以达到MultiAddOne函数的效果。

2 函数打序列桩

ApplyFuncSeq第一个参数是函数名,第二个参数是特定的桩序列参数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey""github.com/agiledragon/gomonkey/test/fake". "github.com/smartystreets/goconvey/convey""testing"
)func TestApplyFuncSeq(t *testing.T) {Convey("TestApplyFuncSeq", t, func() {Convey("default times is 1", func() {info1 := "hello cpp"info2 := "hello golang"info3 := "hello gomonkey"outputs := []OutputCell{{Values: Params{info1, nil}},// 模拟函数的第1次输出{Values: Params{info2, nil}},// 模拟函数的第2次输出{Values: Params{info3, nil}},// 模拟函数的第3次输出}patches := ApplyFuncSeq(fake.ReadLeaf, outputs)defer patches.Reset()output, err := fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info2)output, err = fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info3)})Convey("retry succ util the third times", func() {info1 := "hello cpp"outputs := []OutputCell{{Values: Params{"", fake.ErrActual}, Times: 2},// 模拟函数的第1次输出{Values: Params{info1, nil}},// 模拟函数的第2次输出}patches := ApplyFuncSeq(fake.ReadLeaf, outputs)defer patches.Reset()output, err := fake.ReadLeaf("")So(err, ShouldEqual, fake.ErrActual)output, err = fake.ReadLeaf("")So(err, ShouldEqual, fake.ErrActual)output, err = fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)})Convey("batch operations failed on the third time", func() {info1 := "hello gomonkey"outputs := []OutputCell{{Values: Params{info1, nil}, Times: 2},{Values: Params{"", fake.ErrActual}},}patches := ApplyFuncSeq(fake.ReadLeaf, outputs)defer patches.Reset()output, err := fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = fake.ReadLeaf("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = fake.ReadLeaf("")So(err, ShouldEqual, fake.ErrActual)})})
}

3、函数变量打桩

ApplyFuncVar 第一个参数是函数变量的地址,第二个参数是桩函数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey""github.com/agiledragon/gomonkey/test/fake". "github.com/smartystreets/goconvey/convey""testing"
)func TestApplyFuncVar(t *testing.T) {Convey("TestApplyFuncVar", t, func() {Convey("for succ", func() {str := "hello"patches := ApplyFuncVar(&fake.Marshal, func (_ interface{}) ([]byte, error) {return []byte(str), nil})// fake.Marshal是函数变量defer patches.Reset()bytes, err := fake.Marshal(nil)So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, str)})Convey("for fail", func() {patches := ApplyFuncVar(&fake.Marshal, func (_ interface{}) ([]byte, error) {return nil, fake.ErrActual})defer patches.Reset()_, err := fake.Marshal(nil)So(err, ShouldEqual, fake.ErrActual)})})
}

4、函数变量打序列桩
ApplyFuncVarSeq 第一个参数是函数变量地址,第二个参数是特定的桩序列参数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey""github.com/agiledragon/gomonkey/test/fake". "github.com/smartystreets/goconvey/convey""testing"
)func TestApplyFuncVarSeq(t *testing.T) {Convey("TestApplyFuncVarSeq", t, func() {Convey("default times is 1", func() {info1 := "hello cpp"info2 := "hello golang"info3 := "hello gomonkey"outputs := []OutputCell{{Values: Params{[]byte(info1), nil}},{Values: Params{[]byte(info2), nil}},{Values: Params{[]byte(info3), nil}},}patches := ApplyFuncVarSeq(&fake.Marshal, outputs)defer patches.Reset()bytes, err := fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info1)bytes, err = fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info2)bytes, err = fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info3)})Convey("retry succ util the third times", func() {info1 := "hello cpp"outputs := []OutputCell{{Values: Params{[]byte(""), fake.ErrActual}, Times: 2},{Values: Params{[]byte(info1), nil}},}patches := ApplyFuncVarSeq(&fake.Marshal, outputs)defer patches.Reset()bytes, err := fake.Marshal("")So(err, ShouldEqual, fake.ErrActual)bytes, err = fake.Marshal("")So(err, ShouldEqual, fake.ErrActual)bytes, err = fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info1)})Convey("batch operations failed on the third time", func() {info1 := "hello gomonkey"outputs := []OutputCell{{Values: Params{[]byte(info1), nil}, Times: 2},{Values: Params{[]byte(""), fake.ErrActual}},}patches := ApplyFuncVarSeq(&fake.Marshal, outputs)defer patches.Reset()bytes, err := fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info1)bytes, err = fake.Marshal("")So(err, ShouldEqual, nil)So(string(bytes), ShouldEqual, info1)bytes, err = fake.Marshal("")So(err, ShouldEqual, fake.ErrActual)})})
}

5、全局变量打桩

ApplyGlobalVar 第一个参数是全局变量的地址,第二个参数是全局变量的桩。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey". "github.com/smartystreets/goconvey/convey""testing"
)var num = 10 //全局变量func TestApplyGlobalVar(t *testing.T) {Convey("TestApplyGlobalVar", t, func() {Convey("change", func() {patches := ApplyGlobalVar(&num, 150)defer patches.Reset()So(num, ShouldEqual, 150)})Convey("recover", func() {So(num, ShouldEqual, 10)})})
}

6、成员方法打桩

ApplyMethod 第一个参数是目标类的指针变量的反射类型,第二个参数是字符串形式的方法名,第三个参数是桩函数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey". "github.com/smartystreets/goconvey/convey""gomonkeytest/fake""reflect""testing"
)func TestApplyMethod(t *testing.T) {slice := fake.NewSlice()var s *fake.SliceConvey("TestApplyMethod", t, func() {Convey("for succ", func() {err := slice.Add(1)So(err, ShouldEqual, nil)patches := ApplyMethod(reflect.TypeOf(s), "Add", func(_ *fake.Slice, _ int) error {return nil})defer patches.Reset()err = slice.Add(1)So(err, ShouldEqual, nil)err = slice.Remove(1)So(err, ShouldEqual, nil)So(len(slice), ShouldEqual, 0)})Convey("for already exist", func() {err := slice.Add(2)So(err, ShouldEqual, nil)patches := ApplyMethod(reflect.TypeOf(s), "Add", func(_ *fake.Slice, _ int) error {return fake.ErrElemExsit})defer patches.Reset()err = slice.Add(1)So(err, ShouldEqual, fake.ErrElemExsit)err = slice.Remove(2)So(err, ShouldEqual, nil)So(len(slice), ShouldEqual, 0)})Convey("two methods", func() {err := slice.Add(3)So(err, ShouldEqual, nil)defer slice.Remove(3)patches := ApplyMethod(reflect.TypeOf(s), "Add", func(_ *fake.Slice, _ int) error {return fake.ErrElemExsit})defer patches.Reset()patches.ApplyMethod(reflect.TypeOf(s), "Remove", func(_ *fake.Slice, _ int) error {return fake.ErrElemNotExsit})err = slice.Add(2)So(err, ShouldEqual, fake.ErrElemExsit)err = slice.Remove(1)So(err, ShouldEqual, fake.ErrElemNotExsit)So(len(slice), ShouldEqual, 1)So(slice[0], ShouldEqual, 3)})Convey("one func and one method", func() {err := slice.Add(4)So(err, ShouldEqual, nil)defer slice.Remove(4)patches := ApplyFunc(fake.Exec, func(_ string, _ ...string) (string, error) {return outputExpect, nil})defer patches.Reset()patches.ApplyMethod(reflect.TypeOf(s), "Remove", func(_ *fake.Slice, _ int) error {return fake.ErrElemNotExsit})output, err := fake.Exec("", "")So(err, ShouldEqual, nil)So(output, ShouldEqual, outputExpect)err = slice.Remove(1)So(err, ShouldEqual, fake.ErrElemNotExsit)So(len(slice), ShouldEqual, 1)So(slice[0], ShouldEqual, 4)})})
}

7、成员方法打序列桩

ApplyMethodSeq 第一个参数是目标类的指针变量的反射类型,第二个参数是字符串形式的方法名,第三参数是特定的桩序列参数。测试完成后,patches 对象通过 Reset 成员方法删除所有测试桩。

package testimport (. "github.com/agiledragon/gomonkey""github.com/agiledragon/gomonkey/test/fake". "github.com/smartystreets/goconvey/convey""reflect""testing"
)func TestApplyMethodSeq(t *testing.T) {e := &fake.Etcd{}Convey("TestApplyMethodSeq", t, func() {Convey("default times is 1", func() {info1 := "hello cpp"info2 := "hello golang"info3 := "hello gomonkey"outputs := []OutputCell{{Values: Params{info1, nil}},{Values: Params{info2, nil}},{Values: Params{info3, nil}},}patches := ApplyMethodSeq(reflect.TypeOf(e), "Retrieve", outputs)defer patches.Reset()output, err := e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info2)output, err = e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info3)})Convey("retry succ util the third times", func() {info1 := "hello cpp"outputs := []OutputCell{{Values: Params{"", fake.ErrActual}, Times: 2},{Values: Params{info1, nil}},}patches := ApplyMethodSeq(reflect.TypeOf(e), "Retrieve", outputs)defer patches.Reset()output, err := e.Retrieve("")So(err, ShouldEqual, fake.ErrActual)output, err = e.Retrieve("")So(err, ShouldEqual, fake.ErrActual)output, err = e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)})Convey("batch operations failed on the third time", func() {info1 := "hello gomonkey"outputs := []OutputCell{{Values: Params{info1, nil}, Times: 2},{Values: Params{"", fake.ErrActual}},}patches := ApplyMethodSeq(reflect.TypeOf(e), "Retrieve", outputs)defer patches.Reset()output, err := e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = e.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = e.Retrieve("")So(err, ShouldEqual, fake.ErrActual)})})
}

8、接口打桩

package testimport (. "github.com/agiledragon/gomonkey""github.com/agiledragon/gomonkey/test/fake". "github.com/smartystreets/goconvey/convey""reflect""testing"
)func TestApplyInterfaceReused(t *testing.T) {e := &fake.Etcd{}Convey("TestApplyInterfaceReused", t, func() {patches := ApplyFunc(fake.NewDb, func(_ string) fake.Db {return e})defer patches.Reset()db := fake.NewDb("mysql")Convey("TestApplyInterface", func() {info := "hello interface"patches.ApplyMethod(reflect.TypeOf(e), "Retrieve",func(_ *fake.Etcd, _ string) (string, error) {return info, nil})output, err := db.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info)})Convey("TestApplyInterfaceSeq", func() {info1 := "hello cpp"info2 := "hello golang"info3 := "hello gomonkey"outputs := []OutputCell{{Values: Params{info1, nil}},{Values: Params{info2, nil}},{Values: Params{info3, nil}},}patches.ApplyMethodSeq(reflect.TypeOf(e), "Retrieve", outputs)output, err := db.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info1)output, err = db.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info2)output, err = db.Retrieve("")So(err, ShouldEqual, nil)So(output, ShouldEqual, info3)})})
}

总结

在我看来,gomonkey是弥补了goconvey的不足,两者一起使用可以满足基本需要。goconvey负责断言,gomonkey负责为变量和函数打桩,构造各种测试条件。

http://www.lryc.cn/news/570835.html

相关文章:

  • Android Studio中xml预览不显示问题解决办法
  • ioftpd 之 tls
  • HTTP协议简易入门
  • Velocity提取模板变量
  • php小偷程序实例代码
  • JavaWeb(cekditorsmartupload)
  • Asp.Net的简介
  • 安 利的骗局与真相,关于美国安 利的真实情况
  • 电磁场与电磁波篇---介质媒质导体
  • java实现分页数据每页按比率展示不同类型的数据
  • [转]Visual Studio 各版本区别
  • JDK和JRE官方下载地址
  • 操作系统期末复习整理知识点+习题练习
  • PHP基础篇:empty() 和 isset() 的区别介绍
  • 使用STM32的FLASH保存数据
  • HashiCorp Vault核心应用场景深度解析,国产化替代有什么备选方案
  • JDK1.6官方下载 JDK6官方下载地址
  • C# 取消按钮焦点 (非自定义控件)
  • C# DataTable 自动新增列并赋值
  • 优秀国外博客推荐
  • 史上最全的CSS hack方式一览
  • 第三方登录微信登录流程
  • 各种游戏搬砖ip工具,刷数据IP工具介绍
  • 彻底解决快播不可点播方法
  • 借网上盛传2000w记录介绍多进程处理
  • 启动应用程序出现taskmgr.exe找不到问题解决
  • 使用Garageband给iPhone设置铃声
  • Intel, AMD及VIA CPU的微架构(36)
  • Linux入门(十五)jq 命令解析JSON的安装、使用
  • BeckHoff <---> sartorius天平 采用 EL6002 (RS232)串口通讯