Published on

Get started with GoMock

Authors
  • avatar
    Name
    Gene Zhang
    Twitter

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

  1. 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.

  1. 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.

  1. 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.