This is the fourth in a series of tutorials on Go language unit testing from zero to slip. It introduces how to use monkey in unit testing.
In the previous "Go single test series 5 - mock interface test", we introduced how to use gomock and gostub tools to mock interface and pile driving in unit test.
In this article, we will introduce a more powerful piling tool - monkey, which supports piling for arbitrary functions and methods.
The sample code of Go single test from zero to slide series has been uploaded to Github, click 👉🏻 https://github.com/go-quiz/golang-unit-test-demo View the complete source code.
monkey
introduce
monkey It is a very common piling tool in Go unit testing. It rewrites the executable file through assembly language at run time and jumps the implementation of objective function or method to pile implementation. Its principle is similar to hot patch.
The monkey library is very powerful, but you should pay attention to the following when using it:
- monkey does not support inline functions. When testing, you need to turn off the inline optimization of Go language through the command line parameter - gcflags=-l.
- monkey is not thread safe, so don't use it in concurrent unit tests.
install
go get bou.ke/monkey
Use example
Suppose that the middle office of your company provides a user center library varys, which can easily obtain user related information according to uid. However, when you write code, the library has not been implemented, or the library needs to be requested by the intranet, but you don't have this ability now. At this time, you need to do some mock work to write unit tests for MyFunc.
// func.go func MyFunc(uid int64)string{ u, err := varys.GetInfoByUID(uid) if err != nil { return "welcome" } // Here are some logic codes return fmt.Sprintf("hello %s\n", u.Name) }
We use the monkey library for varys Getinfobyuid for piling.
// func_test.go func TestMyFunc(t *testing.T) { // Yes, varys Getinfobyuid for piling // & varys. Is returned regardless of the uid passed in UserInfo{Name: "liwenzhou"}, nil monkey.Patch(varys.GetInfoByUID, func(int64)(*varys.UserInfo, error) { return &varys.UserInfo{Name: "liwenzhou"}, nil }) ret := MyFunc(123) if !strings.Contains(ret, "liwenzhou"){ t.Fatal() } }
Perform unit tests:
Note: the - gcflags=-l parameter is added here to prevent inline optimization.
go test -run=TestMyFunc -v -gcflags=-l
Output:
=== RUN TestMyFunc --- PASS: TestMyFunc (0.00s) PASS ok monkey_demo 0.009s
In addition to mocking functions, monkey also supports mocking methods.
// method.go type User struct { Name string Birthday string } // CalcAge calculates user age func (u *User) CalcAge() int { 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 get user related information func (u *User) GetInfo()string{ age := u.CalcAge() if age <= 0 { return fmt.Sprintf("%s It's mysterious. We don't know yet ta. ", u.Name) } return fmt.Sprintf("%s this year%d Years old, ta It's our friend.", u.Name, age) }
If the function of the CalcAge method has not been completed when we write the unit test for GetInfo, we can use monkey at this time.
// method_test.go func TestUser_GetInfo(t *testing.T) { var u = &User{ Name: "q1mi", Birthday: "1990-12-20", } // Piling for object method monkey.PatchInstanceMethod(reflect.TypeOf(u), "CalcAge", func(*User)int { return 18 }) ret := u.GetInfo() // An internal call to the u.CalcAge method returns 18 if !strings.Contains(ret, "friend"){ t.Fatal() } }
Perform unit tests:
❯ go test -run=User -v === RUN TestUser_GetInfo --- PASS: TestUser_GetInfo (0.00s) PASS ok monkey_demo 0.012s
monkey can basically meet any needs we need in unit testing.
There is also a reference monkey Library in the community gomonkey The principle and use process of the library are basically similar, so I won't be verbose here. In addition, there are other piling tools in the community, such as GoStub (the previous article introduced piling for global variables), etc.
Skilled use of various piling tools can enable us to write qualified unit tests faster and escort our software.
summary
Through two examples of external function dependency and internal method dependency, this paper introduces how to use monkey to analyze the dependent functions and methods.
In the next article, we will introduce the common tool for writing unit tests - goconvey.