At work, many companies require efficiency and automatic testing
During the actual landing process, it is found that the current service may rely on the data and interfaces of other services for unit testing and automated testing
In the process of single test or automation, the test may fail or block due to other service reasons or environmental factors
This is a problem that must be solved. We can use the mock tool provided by golang to complete it. We can pile data and mock data in some necessary places
What is gomock?
It is an official framework for mock data
The official also provides mockgen tool to help us generate test code
The project address on github is: github com/golang/mock
The official introduction of gomock is as follows:
gomock is a mocking framework for Go programming language. It integrates well with Go's built-in test package, but it can also be used in other environments.
How to use gomock?
Using gomock is also very simple. First go get the corresponding tools gomock and mockgen
go get -u github.com/golang/mock/gomock go get -u github.com/golang/mock/mockgen
You can write a demo to practice
The directory structure is like this
gomock_test ├── go.mod ├── go.sum ├── main.go └── myfunc ├── mock_myfunc.go ├── myfunc.go ├── myuser.go └── myuser_test.go
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-5r1xnval-1640937816719)( https://upload-images.jianshu.io/upload_images/26809252-166fbe55a12ae403.png?imageMogr2/auto -orient/strip%7CimageView2/2/w/1240)]
- mock_myfunc.go is generated using the mockgen tool
- myfunc.go is mainly used to simulate the underlying implementation of the call
- myuser.go is mainly to call myfunc Interface in go
- myuser_test.go is the corresponding single test file
myfunc.go
- Write an interface with a GetInfo() string method to simulate obtaining information
package myfunc type MyFunc interface { GetInfo() string }
myuser.go
- Call myfunc Go, call the interface to get information
package myfunc func getUser(m MyFunc) string { user := m.GetInfo() return user }
Generation of mock file
mock_myfunc.go
This file is not written by ourselves, but generated by mockgen tool. The generation method is as follows:
In myfunc Execute the following statement under the same level directory of go, and fill in the source file and target file to generate a new mock file
mockgen -source=myfunc.go -destination=mock_myfunc.go
We can see the help document of mockgen and other parameters for us to use
# mockgen mockgen has two modes of operation: source and reflect. Source mode generates mock interfaces from a source file. It is enabled by using the -source flag. Other flags that may be useful in this mode are -imports and -aux_files. Example: mockgen -source=foo.go [other options] Reflect mode generates mock interfaces by building a program that uses reflection to understand interfaces. It is enabled by passing two non-flag arguments: an import path, and a comma-separated list of symbols. Example: mockgen database/sql/driver Conn,Driver -aux_files string (source mode) Comma-separated pkg=path pairs of auxiliary Go source files. -build_flags string (reflect mode) Additional flags for go build. -copyright_file string Copyright file used to add copyright header -debug_parser Print out parser results only. -destination string Output file; defaults to stdout. -exec_only string (reflect mode) If set, execute this reflection program. -imports string (source mode) Comma-separated name=path pairs of explicit imports to use. -mock_names string Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix. -package string Package of the generated code; defaults to the package of the input with a 'mock_' prefix. -prog_only (reflect mode) Only generate the reflection program; write it to stdout and exit. -self_package string The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude. -source string (source mode) Input Go source file; enables source mode. -version Print version. -write_package_comment Writes package documentation comment (godoc) if true. (default true) 2021/10/30 16:43:25 Expected exactly two arguments
Generally used more is
- -Source source file
- -Destination destination file
- -imports depends on the package that needs to be import ed
- -build_flags parameters passed to the build tool
- -aux_ The files interface attaches files when there is more than one file
- -Package sets the package name of the mock file. If it is not set, the package name of the mock file is mock by default_ Enter the package name of the file
The mock files generated by the above instructions are as follows:
- NewMockMyFunc
Create a new mock instance
- EXPECT
An object that allows the caller to indicate the intended use
- GetInfo
The basic method of mock, that is, the method we need to mock
Specific how to use
myuser_test.go
- myuser. The single test file corresponding to go uses the mock method
package myfunc import ( "fmt" "testing" gomock "github.com/golang/mock/gomock" ) func Test_getUser(t *testing.T) { mockCtl := gomock.NewController(t) mockMyFunc := NewMockMyFunc(mockCtl) mockMyFunc.EXPECT().GetInfo().Return("xiaomotong") v := getUser(mockMyFunc) if v == "xiaomotong" { fmt.Println("get user right!") } else { t.Error("get error user") } }
Seeing the above single test files, we can't understand the difference. Let's see how we can write a single test without mock
package myfunc import ( "fmt" "testing" gomock "github.com/golang/mock/gomock" ) func Test_getUser(t *testing.T) { m := myfunc.CreateMyFunc() // That is, you need to create an object yourself v := getUser(m) if v == "xiaomotong" { fmt.Println("get user right!") } else { t.Error("get error user") } }
m := myfunc. When createmyfunc() sees the above sentence, it creates the corresponding object, and then passes the object as a parameter into the getUser function. Under normal circumstances, there is no problem with single test
However, if the MyFunc object is not coded due to external dependencies at this time, it can not block our unit tests
At this time, it is particularly important to use the top mock scheme. You can use the mock method to mock a MyFunc object and set the return value, such as:
mockCtl := gomock.NewController(t) mockMyFunc := NewMockMyFunc(mockCtl) mockMyFunc.EXPECT().GetInfo().Return("xiaomotong")
The result of executing the above code is as follows:
> go test get user right! PASS ok mygomock/myfunc 0.427s
Interested friends can use it and become more familiar with it
What are the benefits of using gomock?
- gomock implements a relatively complete interface based Mock function, which can be well integrated with the built-in testing package of Golang, and can also be used in other testing environments
- Learning cost is low and can be started soon
Tools need to be used to give play to their value. What you need can be used
Welcome to like, follow and collect
My friends, your support and encouragement are the driving force for me to insist on sharing and improve quality
Well, that's all for this time
Common technologies are open, and our mentality should be open. Embrace change, live in the sun and strive to move forward.