美文网首页
go monkey和gostub打桩工具

go monkey和gostub打桩工具

作者: 彳亍口巴 | 来源:发表于2022-01-10 22:29 被阅读0次

    使用gostub进行打桩

    GoStub是一个单元测试中的打桩工具,它支持为全局变量、函数等打桩。

    安装

    go get github.com/prashantv/gostub
    

    使用示例

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    var maxNum int
    
    type Person struct {
        Id   int
        name string
    }
    
    func main() {
    
    }
    
    func Func01() int {
        res, _ := json.Marshal(Person{
            Id: 1, name: "string",
        })
        var person Person
        err := json.Unmarshal(res, &person)
        if err != nil {
            fmt.Println(err)
        }
    
        return RPCFunc()+maxNum
    }
    
    var RPCFunc = func() int {
        fmt.Println("调用rpc")
        return maxNum
    }
    
    

    //测试代码

    package main
    
    import (
        "github.com/prashantv/gostub"
        "testing"
    )
    
    func TestFunc01(t *testing.T) {
        tests := []struct {
            name string
            want int
        }{
            // TODO: Add test cases.
            {name: "test01", want: 21},
        }
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
                // 对RPCFunc函数变量打桩,返回结果为1
                stubs := gostub.StubFunc(&RPCFunc, 1)
                // 对变量maxNum打桩,使得maxNum每次都是20
                stubs = stubs.Stub(&maxNum, 20)
                defer stubs.Reset()
                if got := Func01(); got != tt.want {
                    t.Errorf("Func01() = %v, want %v", got, tt.want)
                }
            })
        }
    }
    
    

    执行结果go test -v

    === RUN   TestFunc01
    === RUN   TestFunc01/test01
    --- PASS: TestFunc01 (0.00s)
        --- PASS: TestFunc01/test01 (0.00s)
    PASS
    ok      smalltest/go_test/stub_test     0.152s
    

    使用monkey进行打桩

    介绍

    monkey是一个Go单元测试中十分常用的打桩工具,它在运行时通过汇编语言重写可执行文件,将目标函数或方法的实现跳转到桩实现,其原理类似于热补丁。

    monkey库很强大,但是使用时需注意以下事项:

    • monkey不支持内联函数,在测试的时候需要通过命令行参数-gcflags=-l关闭Go语言的内联优化。
    • monkey不是线程安全的,所以不要把它用到并发的单元测试中。

    安装

    go get bou.ke/monkey
    

    使用示例

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func GetAge(a int64) int64 {
        return CalcAge(a) + a
    }
    
    func CalcAge(a int64) int64 {
        fmt.Println("调用CalcAge")
        if a == 0 {
            return 1
        }
        return 20
    }
    
    type User struct {
        Name     string
        Birthday string
    }
    
    // CalcAge 计算用户年龄
    func (u *User) CalcAge(a int64) int {
        fmt.Println("调用")
        t, err := time.Parse("2006-01-02", u.Birthday)
        if err != nil {
            return -1
        }
        return int(time.Now().Sub(t).Hours()/24.0) / 365
    }
    
    // GetInfo 获取用户相关信息
    func (u *User) GetInfo(a int64) string {
        fmt.Println(a)
        age := u.CalcAge(a)
        if age <= 0 {
            return fmt.Sprintf("%s很神秘,我们还不了解ta。", u.Name)
        }
        return fmt.Sprintf("%s今年%d岁了,ta是我们的朋友。", u.Name, age)
    }
    
    

    测试代码

    package main
    
    import (
        "fmt"
        "reflect"
        "testing"
    
        "bou.ke/monkey"
    )
    
    func TestGetAge(t *testing.T) {
        monkey.Patch(CalcAge, func(a int64) int64 {
            return 100
        })
        type args struct {
            a int64
        }
        tests := []struct {
            name string
            args args
            want int64
        }{
            // TODO: Add test cases.
            {name: "monkey_1", args: args{10}, want: 110},
            {name: "monkey_2", args: args{80}, want: 180},
        }
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
    
                if got := GetAge(tt.args.a); got != tt.want {
                    t.Errorf("GetAge() = %v, want %v", got, tt.want)
                }
            })
        }
    }
    
    func TestUser_GetInfo(t *testing.T) {
        type fields struct {
            Name     string
            Birthday string
        }
        type args struct {
            a int64
        }
        tests := []struct {
            name   string
            fields fields
            args   args
            want   string
        }{
            // TODO: Add test cases.
            {name: "getInfo_1", fields: fields{Name: "zzr", Birthday: "1995-03-08"}, args: args{a: 10}, want: fmt.Sprintf("%s今年%d岁了,ta是我们的朋友。", "zzr", 18)},
        }
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
                u := &User{
                    Name:     tt.fields.Name,
                    Birthday: tt.fields.Birthday,
                }
                // 为对象方法打桩
                monkey.PatchInstanceMethod(reflect.TypeOf(u), "CalcAge", func(*User, int64) int {
                    return 18
                })
    
                if got := u.GetInfo(tt.args.a); got != tt.want {
                    t.Errorf("GetInfo() = %v, want %v", got, tt.want)
                }
            })
        }
    }
    
    

    monkey不仅可以对函数进行打桩,也可以对方法进行打桩,上述代码演示了其为函数以及方法打桩的过程

    相关文章

      网友评论

          本文标题:go monkey和gostub打桩工具

          本文链接:https://www.haomeiwen.com/subject/olpvcrtx.html