mock
A lightweight Go mock generator that creates struct-based mocks from interfaces using //go:generate directives.
How it works
- Annotate any interface with
//go:generate go tool mock
- Run
go generate ./...
- A
gen_<filename>_mock.go file is created alongside the source file
For each annotated interface, mock generates a struct where every method is backed by a function field. This makes mocks trivial to set up inline in tests — no reflection, no DSL, just plain Go.
Installation
As a Go tool (recommended) - tracked in your module and versioned with it:
go get -tool codeberg.org/datek/mock/cmd/mock@latest
This adds a tool directive to your go.mod and makes the binary available via go tool mock.
As a standalone binary:
go install codeberg.org/datek/mock/cmd/mock@latest
Usage
1. Annotate your interfaces
// service.go
package mypackage
//go:generate go tool mock
type UserStore interface {
GetUser(id int) (*User, error)
SaveUser(u *User) error
DeleteUser(id int)
}
Only interfaces immediately preceded by //go:generate go tool mock are processed. Interfaces without the directive are left untouched.
2. Generate the mocks
go generate ./...
This produces gen_service_mock.go in the same package:
// Code generated by mock; DO NOT EDIT.
package mypackage
type UserStoreMock struct {
GetUserMock func(id int) (*User, error)
SaveUserMock func(u *User) error
DeleteUserMock func(id int)
}
func (mock *UserStoreMock) GetUser(id int) (*User, error) {
return mock.GetUserMock(id)
}
func (mock *UserStoreMock) SaveUser(u *User) error {
return mock.SaveUserMock(u)
}
func (mock *UserStoreMock) DeleteUser(id int) {
mock.DeleteUserMock(id)
}
var _ UserStore = &UserStoreMock{}
The var _ UserStore = &UserStoreMock{} line provides a compile-time guarantee that the mock fully satisfies the interface.
3. Use the mock in tests
// service_test.go
package mypackage_test
import (
"errors"
"testing"
)
func TestGetUserReturnsError(t *testing.T) {
store := &UserStoreMock{
GetUserMock: func(id int) (*User, error) {
return nil, errors.New("not found")
},
}
svc := NewUserService(store)
_, err := svc.GetUser(42)
if err == nil {
t.Fatal("expected error, got nil")
}
}
You only need to set the function fields relevant to your test. Unset fields will panic if called, catching unexpected interactions early.
Example with multiple interfaces
// repo.go
package orders
//go:generate go tool mock
type OrderRepo interface {
Find(id string) (*Order, error)
Create(o *Order) error
}
//go:generate go tool mock
type PaymentGateway interface {
Charge(amount int, token string) (string, error)
}
Running go generate produces mocks for both OrderRepo and PaymentGateway in a single gen_repo_mock.go file. Interfaces in the same file without the directive (e.g. a third AuditLog interface) are skipped.
Using the library directly
The Generate function is exported and can be used programmatically:
import "codeberg.org/datek/mock"
src, _ := os.ReadFile("service.go")
output, err := mock.Generate(src, "service.go")
if err != nil {
log.Fatal(err)
}
os.WriteFile("gen_service_mock.go", output, 0644)
License
MIT