Skip to content

Repository files navigation

tinymock

Idiomatic mock generator for Go without any third-party runtime dependency.

//go:generate tinymock
type Starter interface {
	Start()
}

//go:generate tinymock
type Stopper interface {
	Stop()
}

//go:generate tinymock
type Engine interface {
	Starter
	Stopper
}

Just put go:generate tinymock directly before the interface you want to mock and run go generate to generate the mocks. That's it.

Installation

go install github.com/yonedash/tinymock/cmd/tinymock@latest

Usage

First, create an interface you want to mock. Then add a go:generate directive that runs tinymock. You don't need to configure anything else.

//go:generate tinymock
type Foo interface {
	Bar()
}

The go:generate tinymock directive must be placed directly before the interface declaration it targets.

Finally, run go generate to generate the mocks. If your source file is called myfile.go, all mocks from that file will be generated in myfile_mock.go. Each interface still needs its own go:generate tinymock directive.

The relevant part of the generated mock for our Foo example looks like this:

var _ Foo = FooMock{}

type FooMock struct {
	MockBar func()
}

func (m FooMock) Bar() {
	if m.MockBar == nil {
		panic("Foo.Bar is not mocked")
	}
	m.MockBar()
}

The generated mock is a lightweight test double: just ordinary Go code consisting of a struct with function fields and methods that call those functions. The var _ Foo = FooMock{} line makes the compiler verify that FooMock implements Foo.

Depending on how it is used in a test, the mock can act as a stub (by providing predefined behavior) or as a spy (by allowing the test to verify interactions manually). It does not provide built-in expectations, argument matching, call ordering, or automatic verification.

There is no runtime reflection, registration step, or separate configuration format to learn. You configure the mock by assigning functions to its fields:

mock := FooMock{
	MockBar: func() {
		// Test behavior here
	},
}

mock.Bar()

Each generated method has a corresponding function field on the mock. You only need to provide function fields for the methods used by your test. Calling an unconfigured method causes the mock to panic with a helpful message.

The generated *_mock.go files are managed by tinymock and should not be edited manually.

What is supported?

tinymock generates mocks (lightweight test doubles) for Go interfaces. It supports:

  • interface methods, including arguments and return values
  • embedded interfaces
  • embedded interfaces from other packages, such as io.Reader

For example:

package example

import "io"

//go:generate tinymock
type Reader interface {
	io.Reader
}

tinymock generates a mock for the local Reader interface, including the methods provided by io.Reader.

Why another mocking tool?

I could not find a mocking tool that satisfied my inner zen. I don't like having potentially thousands of separate generated files scattered around my project when each file contains the mock for only one type. That's why tinymock can manage multiple mocks within the same file.

All mocks from foo.go are written to foo_mock.go, all mocks from bar.go are written to bar_mock.go, and so on. This keeps the number of generated files under control while still keeping the mocks close to the code they belong to.

I also don't like having to learn a separate configuration format or workflow just to generate simple mocks. They didn’t feel Go-like to me. With tinymock, the generation directive lives next to the interface it targets.

tinymock is intentionally small and focused. If you need expectations, call-order assertions, automatic argument matching, or other advanced mocking features, another tool may be a better fit.

If you want simple, idiomatic Go mocks without repeatedly writing the same boilerplate, tinymock is for you.

About

tinymock is an idiomatic test double generation tool for Go.

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages