- Published on
Get started with GoMock
- Authors
- Name
- Gene Zhang
Full example code
https://github.com/zhang35/gomock-example
Generate mocks for interfaces
mockgen -source=doer.go -package mocks -destination mocks/mock_doer.go
Example testing code
├── doer
│ ├── doer.go
│ └── mocks
│ └── mock_doer.go
├── match
│ └── oftype.go
├── user
│ ├── user.go
│ └── user_test.go
user/user.go
:
// Package user provides a simple user struct with a Doer interface.
package user
import "github.com/zhang35/gomock-example/doer"
// User uses a Doer to do something.
type User struct {
Doer doer.Doer
}
// Use uses the Doer to do some work.
func (u *User) Use(n int, s string) error {
return u.Doer.DoSomething(n, s)
}
doer/doer.go
:
// Package doer provides an interface for doing something.
package doer
// Doer interface has a method that does something.
//
//go:generate mockgen -source=doer.go -package mocks -destination mocks/mock_doer.go
type Doer interface {
DoSomething(int, string) error
}
match/ofType.go
:
package match
import (
"reflect"
"github.com/golang/mock/gomock"
)
// gomock/matchers.go excerpt
// type Matcher interface {
// Matches(x interface{}) bool
// String() string
// }
type ofType struct{ t string }
// OfType returns a gomock.Matcher that matches an interface{} value if it is of the specified type.
func OfType(t string) gomock.Matcher {
return &ofType{t}
}
func (o *ofType) Matches(x interface{}) bool {
return reflect.TypeOf(x).String() == o.t
}
func (o *ofType) String() string {
return "is of type " + o.t
}
Create tests with mocks
user/user_test.go
:
func TestUse(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockDoer := mocks.NewMockDoer(mockCtrl)
testUser := user.User{
Doer: mockDoer,
}
// Expect Do to be called once with 123 and "Hello GoMock" as parameters, and return nil from the mocked call.
// If it's called with different parameters or called more than once, the test will fail.
mockDoer.EXPECT().DoSomething(123, "Hello GoMock").Return(nil).Times(1)
err := testUser.Use(123, "Hello GoMock")
assert.Nil(t, err)
// Expect Do to be called once with 123 and "Hello GoMock" as parameters, and return dummyError from the mocked call.
dummyError := errors.New("dummy error")
mockDoer.EXPECT().DoSomething(123, "Hello GoMock").Return(dummyError).Times(1)
err = testUser.Use(123, "Hello GoMock")
assert.Equal(t, dummyError, err)
// Test with matcher
// Expect Do to be called once with 123 and a string as parameters, and return nil from the mocked call.
mockDoer.EXPECT().
DoSomething(123, match.OfType("string")).
Return(nil).
Times(1)
err = testUser.Use(123, "Any string")
assert.Nil(t, err)
// Asserting call order
callFirst := mockDoer.EXPECT().DoSomething(1, "first this")
mockDoer.EXPECT().DoSomething(2, "then this").After(callFirst)
mockDoer.EXPECT().DoSomething(2, "or this").After(callFirst)
testUser.Use(1, "first this")
testUser.Use(2, "then this")
testUser.Use(2, "or this")
// or use InOrder
gomock.InOrder(
mockDoer.EXPECT().DoSomething(1, "first this"),
mockDoer.EXPECT().DoSomething(2, "then this"),
mockDoer.EXPECT().DoSomething(3, "then this"),
mockDoer.EXPECT().DoSomething(4, "finally this"),
)
testUser.Use(1, "first this")
testUser.Use(2, "then this")
testUser.Use(3, "then this")
testUser.Use(4, "finally this")
// Specifying mock actions
// Call .Do whenever the call is matched.
// % go test -v user/user_test.go
// === RUN TestUse
// Called with x = 3 and y = hello
// --- PASS: TestUse (0.00s)
// PASS
// ok command-line-arguments 0.172s
mockDoer.EXPECT().
DoSomething(gomock.Any(), gomock.Any()).
Return(nil).
Do(func(x int, y string) {
if x > len(y) {
t.Fail()
}
fmt.Println("Called with x =", x, "and y =", y)
})
testUser.Use(3, "hello")
}
Questions
- Does
EXPECT()
have to be followed immediately by the call?
No, it doesn’t have to happen on the next line.
You can write multiple EXPECT() setups first, then run your test logic later. For example:
mock.EXPECT().DoSomething(1).Return(nil).Times(1)
mock.EXPECT().DoSomething(2).Return(nil).Times(1)
someFunctionThatCallsDoSomething() // might trigger DoSomething(1) and DoSomething(2)
As long as the actual calls to DoSomething happen somewhere before mockCtrl.Finish(), you’re good.
- What does
.Return(nil)
mean?
mock.EXPECT().DoSomething().Return(nil)
This means when DoSomething()
is called with the specified parameters, the mock will return nil
— as if the real implementation returned nil
.
- What does
.Times(1)
mean?
mock.EXPECT().DoSomething().Return(nil).Times(1)
It means you expect this method to be called exactly once with the given arguments during the test.