From d971d76d10a6c86f628875e83a85e3217a6a700c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sun, 16 Aug 2026 11:03:58 -0700 Subject: [PATCH] docs: say where a mock for an unexported interface goes The Test doubles section said generated mocks live in a sibling mocks package. For an unexported interface that is impossible: the mock has to import the package to name the types in the interface, and the package own tests have to import the mock, which the compiler rejects as a cycle. Records the second case, and why its destination is scoped to tests -- an unscoped mock puts the mocking library into the dependency graph of everything that imports the package. Co-Authored-By: Claude Opus 5 --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45208fe92..a86545f86 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -201,6 +201,22 @@ checkout runs the version `go.mod` records. Destination files end in `.gen.go` and are committed. Do not use `gen/` for mocks — that name is taken by API code generation. +When the interface is **unexported**, a sibling package cannot work: the mock +has to import the package to name the types in the interface, and the package's +own tests have to import the mock. Generate it into the package instead, with a +destination scoped to tests so the mocking library stays out of the dependency +graph of anything that imports the package: + +```go +// generate.go, in the package that declares the interface +package thispackage + +//go:generate go tool go.uber.org/mock/mockgen -source=thing.go -destination=thing.gen_test.go -package=thispackage +``` + +Either way the directives live in a `generate.go` that holds no code, and the +generated file carries `.gen` so a reader knows not to edit it. + Where call sites would otherwise repeat the same expectations, write a constructor returning a configured mock rather than introducing a hand-written type. The generated mock is still what satisfies the interface.