Unfortunately, the official shutdown in June 2023, but we can still use the branch maintained by the uber team. Gomock is still a framework worth learning in go testing.
introduce
The main function of gomock is to help us simulate complex functions and objects, such as external interfaces/RPC calls/database connections/file operations. Of course, in addition to the gomock community, there are many other mock frameworks, such as mocking for complex objects such as databases. In general, the purpose of mock type framework is to help us simulate the behavior of complex objects and reduce the additional burden of us creating these mock objects manually.
In conjunction with gomock, there is also the mockgen tool to help us generate test code. The following describes how to install and use them.
Install
go get -u /golang/mock/gomock go install /golang/mock/[email protected]
Terminal verification after installation is completedmockgen -version
The output is as follows:
mockgen -version v1.6.0
mockgen
After installing mockgen, we can briefly understand what operations it supports, as well as the commonly used options, terminal inputmockgen
Learn about relevant information:
- There are two operating modes of mockgen: source mode and reflection mode
- Source mode is to generate a mock interface from the source file, and use -source to enable source mode. In addition, parameters such as -imports and -aux_files can also be used together.
- Reflection mode uses reflection to simulate an interface, which requires the imported path and a comma-segmented parameter list to be created.
Here are the general steps for using Gomock:
Defining an interface: First, you need to define an interface to simulate.
-
Generate simulation code: In the package directory containing the interface definition, run the gomock command to generate simulation code. For example: gomock --package=your_package_name
- --package: Specifies the package name where the generated simulation code is located.
- --write_package_comment : Add package comments to the generated code.
- --self_package: Specifies that the generated mock object belongs to the current package.
- --output: Specifies the output file path to generate the simulation code.
Code Example
First declare the interface, create an interface in the file, and use go:generate to help us automatically generate relevant code:
//go:generate mockgen -destination=./mock_human.go -package=main -source= type Human interface { Say(str string) string }
implement:go generate ./...
After that, a mock_human.go file will be generated in the current folder. Let’s write the test file main_test.go to add test cases.
func Test_mock_human(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) ().Say("test").Return("test") if ("test") != "test" { ("say fail") } }
Execute the test and the output is as follows:
=== RUN Test_mock_human --- PASS: Test_mock_human (0.00s) PASS
We are just demonstrating the above examples. Let’s explain the methods used in the method below, and also explain other commonly used methods.
func Test_mock_human(t *) { ("Specify the parameter and return value of the method", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Set the method's entry parameters and return value ().Say("test").Return("test result") if ("test") != "test result" { ("say fail") } }) ("EXPECT assertion method is called", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // The EXPECT() method asserts that the method is called once ().Say("run 1 times").Return("run 1 times result") // If the method is called without using the specified parameters, an error will be reported: aborting test due to missing call(s) if ret := ("run 1 times"); ret != "run 1 times result" { ("say fail:%v", ret) } }) ("Specify the number of calls to the method", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) ().Say("run 2 times").Return("run 2 times result").Times(2) if ret := ("run 2 times"); ret != "run 2 times result" { ("say fail:%v", ret) } if ret := ("run 2 times"); ret != "run 2 times result" { ("say fail:%v", ret) } }) ("No number of calls to the method", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // You can call the mock method anywhere (including 0 times) ().Say("run any times").Return("run any times result").AnyTimes() }) ("Minimum number of calls to specify the method", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Call the mock method at least several times ().Say("min times").Return("min times result").MinTimes(1) if ret := ("min times"); ret != "min times result" { ("say fail:%v", ret) } }) ("Maximum number of calls to specify the method", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Call the mock method several times at most ().Say("max times").Return("max times result").MaxTimes(1) if ret := ("max times"); ret != "max times result" { ("say fail:%v", ret) } }) ("Details of the Implementation of the Specified Method - DoAndReturn", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Override method implementation, custom method mock implementation ().Say("do and return").DoAndReturn(func(str string) string { return "custom return content" }) if ret := ("do and return"); ret != "custom return content" { ("say fail:%v", ret) } }) ("Details of the specified method-Do", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Override method implementation, custom method mock implementation ().Say("do and return").Do(func(s string) { ("Reimplement method, %s", s) }).Return("custom return content") if ret := ("do and return"); ret != "custom return content" { ("say fail:%v", ret) } }) ("No specific parameters specified", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Here it means no matter what string is passed in ().Say(()).Return("any arg is okay2").AnyTimes() if ret := ("1"); ret != "any arg is okay2" { ("say fail:%v", ret) } if ret := ("2"); ret != "any arg is okay2" { ("say fail:%v", ret) } }) ("Specify incoming parameters", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Here it indicates what string must be passed to the parameter ().Say(("valid string")).Return("valid result") if ret := ("valid string"); ret != "valid result" { ("say fail:%v", ret) } }) ("Specify that the incoming parameter is not a specific value", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Here means that the passed parameter cannot be valid string ().Say(("valid string")).Return("valid result") if ret := ("invalid string"); ret != "valid result" { ("say fail:%v", ret) } }) ("Specify that the incoming parameter is nil", func(t *) { ctrl := (t) defer () mockHuman := NewMockHuman(ctrl) // Here means that the passed parameter must be nil ().Say2(()).Return("valid result") if ret := mockHuman.Say2(nil); ret != "valid result" { ("say fail:%v", ret) } }) }
The methods involved and the functions of the methods:
- EXPECT: Used to set expectations for mock object method calls, which can define various expected behaviors of mock methods when they are called, such as the expected number of calls, incoming parameters, returned values, and possible side effects operations.
- Times: Used to specify the expected number of method calls.
- AnyTimes: Indicates that the simulated method can be called any number of times, including 0 times.
- MinTimes: Specifies the minimum number of times the simulation method is called.
- MaxTimes: Specifies the maximum number of times the simulation method is called.
- Do: Execute a custom function when a mock method is called, which can contain some additional logic or side effects.
- DoAndReturn: Similar to Do, but also specifies the return value.
- Eq: Used to verify that the parameters passed in simulation method are equal to the specified value.
- Not: It is often used in conjunction with other matchers to indicate opposite conditions.
- Nil: Used to check whether a value is nil.
The above are the usage methods and some concepts of gomock.
This is the article about detailed explanation of the usage scenarios and methods of gomock in Golang. For more related Go gomock content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!