Mocks¶
go-testgen generates testify mocks for Go interfaces. This page explains when to use them, how they are generated, and how they integrate with the check function pattern.
When Mocks Are Generated¶
Pass --mock-from to gen. Four formats are supported:
Cross-package interface¶
go-testgen gen ./internal/core/services/user Service.CreateUser \
--mock-from userDomain.UserRepository
Full import path (external or stdlib)¶
go-testgen gen --mock-from "io.Writer" --pkg mypkg -o -
go-testgen gen --mock-from "io/fs.FS" --pkg mypkg --output ./mocks/
go-testgen gen --mock-from "net/http.Handler" --pkg mypkg -o -
go-testgen gen --mock-from "github.com/foo/bar.Doer" --pkg mypkg -o ./
When the prefix before the last . contains /, it is treated as a full import path. The interface is loaded directly from that package without resolving through consuming package imports. This works for stdlib, external modules, and in standalone mode.
Standalone mock mode¶
When no positional args are provided but --mock-from is present, go-testgen generates mocks without a consuming package:
go-testgen gen --mock-from "io.Writer" --pkg mypkg --output ./
go-testgen gen --mock-from "io.Writer" --mock-from "io.Reader" \
--pkg mypkg --output ./mocks/
In standalone mode --pkg and --output are required.
Same-package interface (dot prefix)¶
The . prefix tells go-testgen to look for the interface in the package being tested.
Bare interface name¶
When no qualifier or dot is present, go-testgen searches for the interface in the current package.
The flag is repeatable — pass multiple --mock-from flags for functions with multiple interface dependencies:
go-testgen gen ./internal/core/services/order Service.PlaceOrder \
--mock-from orderDomain.OrderRepository \
--mock-from cache.Cache
Existing mock files are never overwritten.
Generated Mock Structure¶
For an interface:
// userDomain package
type UserRepository interface {
CreateUser(ctx context.Context, req *UserCreateRequest) (*User, error)
FindByID(ctx context.Context, id string) (*User, error)
Delete(ctx context.Context, id string) error
}
go-testgen generates:
type mockUserRepository struct {
mock.Mock
}
func (m *mockUserRepository) CreateUser(ctx context.Context, req *userDomain.UserCreateRequest) (*userDomain.User, error) {
args := m.Called(ctx, req)
r, _ := args.Get(0).(*userDomain.User)
return r, args.Error(1)
}
func (m *mockUserRepository) FindByID(ctx context.Context, id string) (*userDomain.User, error) {
args := m.Called(ctx, id)
r, _ := args.Get(0).(*userDomain.User)
return r, args.Error(1)
}
func (m *mockUserRepository) Delete(ctx context.Context, id string) error {
args := m.Called(ctx, id)
return args.Error(0)
}
Key properties:
- All interface methods implemented.
- Pointer and slice returns use comma-ok type assertion (
r, _ := args.Get(0).(*T)) — safe when the mock returnsnil. args.Error(n)handleserrorreturns correctly, includingnil.
Using Mocks in the before Field¶
Mock expectations are set per test case in the before field, not globally:
{
name: "repo returns error",
req: &userDomain.UserCreateRequest{Name: "alice"},
before: func(s *Service) {
s.repo.(*mockUserRepository).
On("CreateUser", mock.Anything, mock.Anything).
Return(nil, errors.New("connection refused"))
},
checks: checkServiceCreateUser(
checkCreateUserError("connection refused"),
),
},
This keeps each test case self-contained: the mock is configured, the function is called, checks run.
Skipping Mock Generation¶
If a mock file already exists (from a previous gen call or written by hand), go-testgen will not overwrite it. Omit --mock-from for subsequent functions in the same package:
# First call — creates the mock
go-testgen gen ./internal/core/services/user Service.CreateUser \
--mock-from userDomain.UserRepository
# Subsequent calls — mock already exists, skip --mock-from
go-testgen gen ./internal/core/services/user Service.FindByID
go-testgen gen ./internal/core/services/user Service.Delete
The report command shows --mock-from flags only for interfaces whose mock file does not yet exist, so you can copy-paste its suggested commands directly.
Manual Mocks¶
You can write mocks by hand or use another tool (e.g., mockery). go-testgen does not require its own generated mocks — it only generates them when --mock-from is passed.