Moq

Moq is a tool that generates a struct from any interface. The struct can be used in test code as a mock of the interface.

preview

Installing

To start using Moq, just run go get:

$ go get github.com/matryer/moq

Usage

moq [flags] source-dir interface [interface2 [interface3 [...]]]
	-fmt string
		go pretty-printer: gofmt, goimports or noop (default gofmt)
	-out string
		output file (default stdout)
	-pkg string
		package name (default will infer)
	-stub
		return zero values when no mock implementation is provided, do not panic
	-skip-ensure
		suppress mock implementation check, avoid import cycle if mocks 
		generated outside of the tested package

Specifying an alias for the mock is also supported with the format 'interface:alias'

Example: moq -pkg different . MyInterface:MyMock

NOTE: source-dir is the directory where the source code (definition) of the target interface is located.
It needs to be a path to a directory and not the import statement for a Go package.

In a command line:

$ moq -out mocks_test.go . MyInterface

In code (for go generate):

package my

//go:generate moq -out myinterface_moq_test.go . MyInterface

type MyInterface interface {
	Method1() error
	Method2(i int)
}

Then run go generate for your package.

How to use it

Mocking interfaces is a nice way to write unit tests where you can easily control the behaviour of the mocked object.

Moq creates a struct that has a function field for each method, which you can declare in your test code.

In this example, Moq generated the EmailSenderMock type:

func TestCompleteSignup(t *testing.T) {

	var sentTo string

	mockedEmailSender = &EmailSenderMock{
		SendFunc: func(to, subject, body string) error {
			sentTo = to
			return nil
		},
	}

	CompleteSignUp("[email protected]", mockedEmailSender)

	callsToSend := len(mockedEmailSender.SendCalls())
	if callsToSend != 1 {
		t.Errorf("Send was called %d times", callsToSend)
	}
	if sentTo != "[email protected]" {
		t.Errorf("unexpected recipient: %s", sentTo)
	}

}

func CompleteSignUp(to string, sender EmailSender) {
	// TODO: this
}

The mocked structure implements the interface, where each method calls the associated function field.

Tips

  • Keep mocked logic inside the test that is using it
  • Only mock the fields you need
  • It will panic if a nil function gets called
  • Name arguments in the interface for a better experience
  • Use closured variables inside your test function to capture details about the calls to the methods
  • Use .MethodCalls() to track the calls
  • Use go:generate to invoke the moq command
  • If Moq fails with a go/format error, it indicates the generated code was not valid.
    You can run the same command with -fmt noop to print the generated source code without attempting to format it.
    This can aid in debugging the root cause.

GitHub

https://github.com/matryer/moq