Mockey

Mockey 是一款简单易用的 Golang 打桩工具库,能够快速方便地进行函数、变量的 mock,目前在字节跳动各业务的单元测试编写中应用较为广泛,其底层是通过运行时改写函数指令实现的猴子补丁(Monkey Patch)

具体介绍可以看官方文档

使用方法

foo/mocki.go
foo/foobar_test.go
foo/bar/foobar.go
package foo

import (
	"reflect"

	"github.com/bytedance/mockey"
)

func MockI(target any, opts ...any) *mockey.MockBuilder {
	if len(opts) == 0 {
		return mockey.Mock(target)
	}

	methodName := opts[0].(string)
	v := reflect.TypeOf(target)
	method, _ := v.MethodByName(methodName)
	fn := method.Func.Interface()
	return mockey.Mock(fn)
}
package bar

type BarInterface interface {
	Foo() string
	Bar() string
}

type privateStruct struct {
}

func (o privateStruct) Foo() string {
	return ""
}

func (o *privateStruct) Bar() string {
	return ""
}

func NewPrivateStruct() BarInterface {
	return &privateStruct{}
}

type PublicStruct struct {
}

func (o PublicStruct) Foo() string {
	return ""
}

func (o *PublicStruct) Bar() string {
	return ""
}
package foo

import (
	"testing"

	"happy-fox-data-library-service/common/foo/bar"

	. "github.com/bytedance/mockey"
	. "github.com/smartystreets/goconvey/convey"
)

func shr(n int, position int) int {
	return n >> position
}

func TestSHR(t *testing.T) {
	PatchConvey("Test shift logical right", t, func() {
		PatchConvey("不mock", func() {
			So(shr(1, 2), ShouldEqual, 0)
			So(shr(2, 2), ShouldEqual, 0)
			So(shr(3, 2), ShouldEqual, 0)
			So(shr(4, 2), ShouldEqual, 1)
		})

		PatchConvey("mock", func() {
			Mock(shr).Return(10).Build()
			So(shr(1, 2), ShouldEqual, 10)
		})
	})
}

func TestMockPublicStructMethods(t *testing.T) {
	PatchConvey("Test mock public struct methods", t, func() {
		PatchConvey("非指针类型receiver", func() {
			o := bar.PublicStruct{}
			Mock(bar.PublicStruct.Foo).Return("hello foo").Build()
			So(o.Foo(), ShouldEqual, "hello foo")
		})
		PatchConvey("指针类型receiver", func() {
			o := bar.PublicStruct{}
			Mock((*bar.PublicStruct).Bar).Return("hello bar").Build()
			So(o.Bar(), ShouldEqual, "hello bar")
		})
	})
}

func TestMockPrivateStructMethods(t *testing.T) {
	PatchConvey("Test mock private struct methods", t, func() {
		PatchConvey("非指针类型receiver", func() {
			o := bar.NewPrivateStruct()
			MockI(o, "Foo").Return("hello foo").Build()
			So(o.Foo(), ShouldEqual, "hello foo")
		})
		PatchConvey("指针类型receiver", func() {
			o := bar.NewPrivateStruct()
			MockI(o, "Bar").Return("hello bar").Build()
			So(o.Bar(), ShouldEqual, "hello bar")
		})
	})
}