go monkey和gostub打桩工具

2022-01-10  本文已影响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库很强大,但是使用时需注意以下事项:

安装

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不仅可以对函数进行打桩,也可以对方法进行打桩,上述代码演示了其为函数以及方法打桩的过程

上一篇下一篇

猜你喜欢

热点阅读