Skip to Content

gofasta g mock

Walks the project’s interface declarations and emits a testify/mock implementation under testutil/mocks/<snake>_mock.go. The generated mock:

  • Embeds testify/mock.Mock so every method gets On(...).Return(...) ergonomics.
  • Includes a compile-time assertion (var _ iface.OrderService = (*OrderServiceMock)(nil)) so a future interface change breaks the build rather than silently producing a non-conforming mock.
  • Picks the right testify accessor per return type (Error, String, Int, Bool, or a nil-safe typed Get assertion for pointer / slice / map / qualified-type returns).
  • Is gofmt-clean out of the box.

Two operating modes: generate one mock for a named interface, or --all to refresh every mock under the standard interface dirs.

Usage

gofasta g mock [InterfaceName] [flags]

The positional arg is the exact interface name (e.g. OrderService, UserRepositoryInterface). Omit it with --all to refresh every mock.

Flags

FlagDefaultDescription
--allfalseRegenerate every mock under app/services/interfaces and app/repositories/interfaces. Ignores the positional arg.
--checkfalseDon’t write — exit non-zero with MOCK_DRIFT if the on-disk mock differs from what would be generated. CI gate.

Examples

Generate one mock:

gofasta g mock OrderService # → testutil/mocks/order_service_mock.go

Refresh every mock after changing several interfaces at once:

gofasta g mock --all

CI: detect mocks that haven’t been regenerated after an interface change:

gofasta g mock --all --check # exit 0 → all mocks in sync # exit !0 → MOCK_DRIFT — re-run without --check to update

CI: check one mock specifically:

gofasta g mock OrderService --check

Output shape

Given:

// app/services/interfaces/order_service.go package interfaces import "context" type OrderService interface { Get(ctx context.Context, id string) (*Order, error) List(ctx context.Context) ([]*Order, error) Archive(ctx context.Context, id string) error }

gofasta g mock OrderService writes:

// testutil/mocks/order_service_mock.go // Code generated by `gofasta g mock`. DO NOT EDIT. // Regenerate by running `gofasta g mock OrderService` (or `--all`). package mocks import ( "context" "myapp/app/services/interfaces" "myapp/app/models" "github.com/stretchr/testify/mock" ) // OrderServiceMock is a testify/mock implementation of interfaces.OrderService. type OrderServiceMock struct { mock.Mock } var _ interfaces.OrderService = (*OrderServiceMock)(nil) func (m *OrderServiceMock) Get(ctx context.Context, id string) (*models.Order, error) { args := m.Called(ctx, id) return func() *models.Order { if v := args.Get(0); v != nil { return v.(*models.Order) } return nil }(), args.Error(1) } func (m *OrderServiceMock) List(ctx context.Context) ([]*models.Order, error) { args := m.Called(ctx) return func() []*models.Order { if v := args.Get(0); v != nil { return v.([]*models.Order) } return nil }(), args.Error(1) } func (m *OrderServiceMock) Archive(ctx context.Context, id string) error { args := m.Called(ctx, id) return args.Error(0) }

The pointer / slice / map / qualified-type returns are guarded with the if v := args.Get(...); v != nil { ... } shim so a nil return value doesn’t panic at runtime.

Where it looks

--all walks two directories:

  • app/services/interfaces/
  • app/repositories/interfaces/

Every interface declared in any *.go (not _test.go) file there is regenerated. Other directories aren’t scanned — interfaces defined elsewhere need the explicit form (gofasta g mock <Name>).

For the single-interface form, the same two directories are searched. An interface declared in both (rare) returns AMBIGUOUS_SYMBOL with the list of files.

Embedded interfaces

The initial release supports flat interfaces only. An interface that embeds another:

type AdminService interface { UserService // embedded — skipped PromoteToAdmin(ctx context.Context, userID string) error }

Will generate a mock with PromoteToAdmin only; the embedded UserService methods are silently dropped. If you need to mock an embedded interface, define the flat version directly or compose mocks at the test site.

Drift detection (--check)

--check compares the generated bytes to the on-disk file. Differences (whitespace-normalized) trigger MOCK_DRIFT. Use this in CI to enforce that interface changes are accompanied by a mock regeneration:

# .github/workflows/ci.yml - run: gofasta g mock --all --check

If it fails, the developer’s fix is gofasta g mock --all locally + commit the updated mock.

Error codes

CodeWhen
INTERFACE_NOT_FOUNDThe named interface isn’t declared in either standard dir (or, with --all, no interfaces exist in either dir).
AMBIGUOUS_SYMBOLThe same interface name is declared in two files. Rename one or use the explicit form.
MOCK_DRIFT--check mode: the on-disk mock differs from what would be generated.
NOT_GOFASTA_PROJECTNo go.mod in the cwd.
AST_PARSE_FAILEDOne of the interface files has a syntax error.
FILE_IOCouldn’t create testutil/mocks/ or write the output file.
Last updated on