Powerful mock generation tool for Go programming language
Powerful mock generation tool for Go programming language
Minimock generates mocks out of Go interface declarations.
The main features of minimock are:
go generate ./... command from within the project's directory.If you use go modules please download the latest binary or install minimock from source:
go install github.com/gojuno/minimock/v3/cmd/minimock@latestIf you don't use go modules please find the latest v2.x binary here or install minimock using v2 branch
…Let's say we have the following interface declaration in github.com/gojuno/minimock/tests package:
type Formatter interface {
Format(string, ...interface{}) string
}This will generate mocks for all interfaces defined in the "tests" package:
$ cd ~/go/src/github.com/gojuno/minimock/tests
$ minimock Here is how to generate a mock for the "Formatter" interface only:
$ cd ~/go/src/github.com/gojuno/minimock/tests
$ minimock -i Formatter Same using the relative package notation:
$ minimock -i ./tests.FormatterSame using the full import path of the source package:
$ minimock -i github.com/gojuno/minimock/tests.Formatter -o ./tests/All the examples above generate ./tests/formatter_mock_test.go file
Now it's time to use the generated mock. There are several ways it can be done.
mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc).FormatMock.Expect("hello %s!", "world").Return("hello world!")The builder pattern is convenient when you have more than one method to mock. Let's say we have an io.ReadCloser interface which has two methods: Read and Close
type ReadCloser interface {
Read(p []byte) (n int, err error)
Close() error
}We can set up a mock using a simple one-liner:
mc := minimock.NewController(t)
readCloserMock := NewReadCloserMock(mc).ReadMock.Expect([]byte(1,2,3)).Return(3, nil).CloseMock.Return(nil)But what if we don't want to check all arguments of the read method? Let's say we just want to check that the second element of the given slice "p" is 2. This is where "Inspect" helper comes into play:
mc := minimock.NewController(t)
readCloserMock := NewReadCloserMock(mc).ReadMock.Inspect(func(p []byte){
assert.Equal(mc, 2, p[1])
}).Return(3, nil).CloseMock.Return(nil)
Let's say we have a mocking interface with function that has many arguments:
type If interface {
Do(intArg int, stringArg string, floatArg float)
}Imagine that you don't want to check all the arguments, just one or two of them. Then we can use ExpectParams helpers, which are generated for each argument:
mc := minimock.NewController(t)
ifMock := NewIfMock(mc).DoMock.ExpectIntArgParam1(10).ExpectFloatArgParam3(10.2).Return()mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc)
formatterMock.FormatMock.When("Hello %s!", "world").Then("Hello world!")
formatterMock.FormatMock.When("Hi %s!", "there").Then("Hi there!")alternatively you can use the one-liner:
formatterMock = NewFormatterMock(mc).FormatMock.When("Hello %s!", "world").Then("Hello world!").FormatMock.When("Hi %s!", "there").Then("Hi there!")mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc).FormatMock.Set(func(string, ...interface{}) string {
return "minimock"
})You can also use invocation counters in your mocks and tests:
mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc)
formatterMock.FormatMock.Set(func(string, ...interface{}) string {
return fmt.Sprintf("minimock: %d", formatterMock.BeforeFormatCounter())
})Imagine you expect mock to be called exactly 10 times.
Then you can set Times helper to check how many times mock was invoked.
mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc).FormatMock.Times(10).Expect("hello %s!", "world").Return("hello world!")There are also cases, when you don't know for sure if the mocking method would be called or not. But you still want to mock it, if it will be called. This is where "Optional" option comes into play:
mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc).FormatMock.Optional().Expect("hello %s!", "world").Return("hello world!")When this option is set, it disables checking the call of mocking method.
Sometimes context gets modified by the time the mocked method is being called.
However, in most cases you don't really care about the exact value of the context argument.
In such cases you can use special minimock.AnyContext variable, here are a couple of examples:
mc := minimock.NewController(t)
senderMock := NewSenderMock(mc).
SendMock.
When(minimock.AnyContext, "message1").Then(nil).
When(minimock.AnyContext, "message2").Then(errors.New("invalid message"))or using Expect:
mc := minimock.NewController(t)
senderMock := NewSenderMock(mc).
SendMock.Expect(minimock.AnyContext, "message").Return(nil)Often we write tons of mocks to test our code but sometimes the tested code stops using mocked dependencies.
You can easily identify this problem by using minimock.NewController instead of just *testing.T.
Alternatively you can use mc.Wait helper if your're testing concurrent code.
These helpers ensure that all your mocks and expectations have been used at least once during the test run.
func TestSomething(t *testing.T) {
// it will mark this example test as failed because there are no calls
// to formatterMock.Format() and readCloserMock.Read() below
mc := minimock.NewController(t)
formatterMock := NewFormatterMock(mc)
formatterMock.FormatMock.Return("minimock")
readCloserMock := NewReadCloserMock(mc)
readCloserMock.ReadMock.Return(5, nil)
}Testing concurrent code is tough. Fortunately minimock.Controller provides you with the helper method that makes testing concurrent code easy. Here is how it works:
func TestSomething(t *testing.T) {
mc := minimock.NewController(t)
//Wait ensures that all mocked methods have been called within the given time span
//if any of the mocked methods have not been called Wait marks the test as failed
defer mc.Wait(time.Second)
formatterMock := NewFormatterMock(mc)
formatterMock.FormatMock.Return("minimock")
//tested code can run the mocked method in a goroutine
go formatterMock.Format("hello world!")
}Writing test is not only mocking the dependencies. Often the test itself contains a lot of boilerplate code. You can generate test stubs using GoUnit tool which has a nice template that uses minimock.
Happy mocking!
No open issues yet, or sync has not completed.