This is a creation in Article, where the information may have evolved or changed.
In the development process often need to cooperate with unit testing, but many times, unit testing needs to rely on some more complex preparations, such as the need to rely on the database environment, the need to rely on the network environment, unit testing has become a very troublesome thing. For example, for example, we need to request a Web page and process the requested data back. At first, I usually start a simple HTTP service before running my unit tests. But this unit test seems to be very cumbersome to measure. Even during the continuous integration process, I wrote a script to automatically start the corresponding service in order to be able to automate the test. Things seem to need some change.
The mock object is born to solve the problem above, the mock (mock) object can simulate the function of the actual dependent object, without the need of very complicated preparation, all you need to do is define the object interface, then implement it, then give it to the test object to use.
Go-mock is a mock library specially developed for go language, which is simple to use and supports automatic generation of code, which can be said to be a rare and good tool. Let me briefly show you how Go-mock works:
The first thing you need to do is to download the dependencies locally:
go get github.com/golang/mock/gomockgo get github.com/golang/mock/mockgen
The first is code-dependent, and the second is the command-line tool (especially useful).
Here's a very simple example to illustrate how Gomock works:
I'm $GOPATH/src
creating a new project under the directory: hellomock
create a new one in the $GOPATH/src/hellomock
directory hellomock.go
, and define an interface Talker
:
package hellomocktype Talker interface { SayHello(word string)(response string)}
Then we need a Talker
struct that implements the function, assuming that we have a scene where we now have a welcome post and a welcome receptionist, and of course the usher can be a person or a parrot. So what we need to do is define a Persion
struct (or a parrot or something else) and implement the Talker
interface:
person.go
package hellomockimport "fmt"type Person struct{ name string}func NewPerson(name string)*Person{ return &Person{ name:name, }}func (p *Person)SayHello(name string)(word string) { return fmt.Sprintf("Hello %s, welcome come to our company, my name is %s",name,p.name) }
Now that we Person
have implemented the Talker
interface, let's make him work now!
Now suppose we have a company that has a receptionist, the sister of our front desk, who implements the Talker
interface. She was able to automatically always be the guest SayHello
:
company.go
package hellomocktype Company struct { Usher Talker}func NewCompany(t Talker) *Company{ return &Company{ Usher:t, }}func ( c Company) Meeting(gusetName string)string{ return c.Usher.SayHello(gusetName)}
Our scene has been designed, so how do we implement unit testing in the traditional way?
company_test.go
package hellomockimport "testing"func TestCompany_Meeting(t *testing.T) { person := NewPerson("王尼美") company := NewCompany(person) t.Log(company.Meeting("王尼玛"))}
Test:
/usr/local/go/bin/go test -v hellomock -run ^TestCompany_Meeting$ company_test.go:8: Hello 王尼玛, welcome come to our company, my name is 王尼美ok hellomock 0.013s
Now we're building a 王尼美
simple one, but now we're going to simulate with mock objects, and we're mockgen
on the scene:
➜ hellomock> mkdir mock ➜ hellomock> mockgen -source=hellomock.go > mock/mock_Talker.go
This time, the file will be generated mock/mock_Talker.go
:
It is important to note that automatically generated files with the same source file under different packages, you need to create a new directory to store
We don't need to care about the content of the generated file, we just need to know how to use it.
mock_Talker.go
Automatically generated by Mockgen. Do not edit!//Source:hellomock.gopackage mock_hellomockimport (gomock "Github.com/golang/mock/gomock")//Mocktalker is a mock of Talker interfacetype mocktalker struct {Ctrl *gomock. Controller Recorder *mocktalkermockrecorder}//Mocktalkermockrecorder is the mock recorder for Mocktalkertype Mocktalke Rmockrecorder struct {Mock *mocktalker}//newmocktalker creates a new mock Instancefunc newmocktalker (Ctrl *gomock. Controller) *mocktalker {mock: = &mocktalker{ctrl:ctrl} mock.recorder = &mocktalkermockrecorder{mock} r Eturn mock}//EXPECT Returns an object it allows the caller to indicate expected Usefunc (_m *mocktalker) EXPECT () *mock Talkermockrecorder {return _m.recorder}//SayHello mocks base methodfunc (_m *mocktalker) SayHello (name string) string {ret: = _m.ctrl.call (_m, "SayHello", name) Ret0, _: = Ret[0]. (string) return ret0}//SayHello indicates an expected call of Sayhellofunc (_MR *mockTalkermockrecorder) SayHello (arg0 interface{}) *gomock. Call {return _mr.mock.ctrl.recordcall (_mr.mock, "SayHello", arg0)}
Next look at how to use this mock object and create a new unit test:
func TestCompany_Meeting2(t *testing.T) { ctl := gomock.NewController(t) mock_talker := mock_hellomock.NewMockTalker(ctl) mock_talker.EXPECT().SayHello(gomock.Eq("王尼玛")).Return("这是自定义的返回值,可以是任意类型。") company := NewCompany(mock_talker) t.Log(company.Meeting("王尼玛")) //t.Log(company.Meeting("张全蛋"))}
Test:
/usr/local/go/bin/go test -v hellomock -run ^TestCompany_Meeting2$ company_test.go:21: 这是自定义的返回值,可以是任意类型。ok hellomock 0.015s
As you can see, the return value we defined on the mock object is returned.
One point to note is that the acceptable parameters of the mock object SayHello
are gomock.Eq(x interface{})
the gomock.Any()
same as, the previous requirement that the test case is in strict compliance with the meal, and the x
second allows any arguments to be passed in. For example, we passed the "Zhangquan egg" in the commented out test, the result is error, the test failed:
/usr/local/go/bin/go test -v hellomock -run ^TestCompany_Meeting2$ controller.go:113: no matching expected call: *mock_hellomock.MockTalker.SayHello([张全蛋])exit status 1FAIL hellomock 0.007s
This article as a gomock, there are many high-level usage, I hope you can explore on their own.
Reference article:
Https://github.com/golang/moc ...
Https://github.com/grpc/grpc-...
Reprint please specify the source http://www.chenquan.me