English | 中文
Mockey is a simple and easy-to-use golang mock library, which can quickly and conveniently mock functions and variables. At present, it is widely used in the unit test writing of ByteDance services. The bottom layer is monkey patch realized by rewriting function instructions at runtime.
go get github.com/bytedance/mockey@latest
import (
"fmt"
"testing"
. "github.com/bytedance/mockey"
. "github.com/smartystreets/goconvey/convey"
)
func Foo(in string) string {
return in
}
type A struct{}
func (a A) Foo(in string) string { return in }
var Bar = 0
func TestMockXXX(t *testing.T) {
PatchConvey("TestMockXXX", t, func() {
Mock(Foo).Return("c").Build() // mock function
Mock(A.Foo).Return("c").Build() // mock method
MockValue(&Bar).To(1) // mock variable
So(Foo("a"), ShouldEqual, "c") // assert `Foo` is mocked
So(new(A).Foo("b"), ShouldEqual, "c") // assert `A.Foo` is mocked
So(Bar, ShouldEqual, 1) // assert `Bar` is mocked
})
// mock is released automatically outside `PatchConvey`
fmt.Println(Foo("a")) // a
fmt.Println(new(A).Foo("b")) // b
fmt.Println(Bar) // 0
}
Mockey is distributed under the Apache License, version 2.0. The licenses of third party dependencies of Mockey are explained here.
go test -gcflags="all=-l -N" -v ./...
-gcflags="all=-l -N"
in the Run/Debug Configurations > Go tool arguments dialog boxBuild()
method was not called: forgot to call Build()
, resulting in no actual effectTarget function does not match exactly:
func TestXXX(t *testing.T) {
Mock((*A).Foo).Return("c").Build()
fmt.Println(A{}.Foo("a")) // enters the original function, because the mock target should be `A.Foo`
a := A{}
Mock(a.Foo).Return("c").Build()
fmt.Println(a.Foo("a")) // enters the original function, because the mock target should be `A.Foo` or extracted from instance `a` using `GetMethod`
}
func TestXXX(t *testing.T) {
PatchConvey("TestXXX", t, func() {
Mock(Foo).Return("c").Build()
go Foo("a") // the timing of executing 'foo' is uncertain
})
// when the main goroutine comes here, the relevant mock has been released by 'PatchConvey'. If 'foo' is executed before this, the mock succeeds, otherwise it fails
fmt.Println("over")
time.Sleep(time.Second)
}
PatchConvey
of the smallest unit. If there is such a need, please get the Mocker
instance and remock.