

新闻资讯
技术学院测试时传指针更难写,因其引入外部可变状态导致测试污染、并发不安全、mock复杂;应优先用值接收者,仅当需修改接收者本身或大对象性能敏感时才用指针。
因为指针会把外部状态带进测试作用域,导致测试间相互污染。比如一个函数接收 *sync.Mutex 或 *sql.DB,你没法在测试里轻易控制它的内部状态,也无法安全地并发运行多个测试用例。
struct{}、int、string)天然隔离,每次传参都是副本,测试互不干扰map、slice、chan 的 struct),测试中修改它会影响其他测试或后续断言仅当方法需要修改接收者本身(不是字段),且该修改是业务语义的一部分时,才应使用指针接收者。否则,优先用值接收者 + 返回新值,测试更干净。
func (s Score) Add(n int) Score 比 func (s *Score) Add(n int) 更易测:输入确定 → 输出确定,无副作用time.Time 是值类型,所有方法都是值接收者;而 bytes.Buffer 是指针接收者,因为它必须 mutate 内部 []byte
接口本身不声明接收者类型,但实现它的具体类型决定了调用方是否能传值或必须传指针。一旦接口被广泛使用,就很难再把指针接收者改成值接收者——会导致大量调用点编译失败。
*T 的强依赖,比如写 func Do(*T) 而非 func Do(T) —— 这会让 mock 实现必须分配堆内存,增加测试复杂度
,需检查是否真有必要用 gomock 生成 mock 时,如果原接口由指针接收者实现,mock 对象也必须是指针类型;而你传给被测函数的若是个值,Go 会静默取地址——但这个地址只在当前作用域有效,容易引发 panic 或未定义行为。
type Service interface {
Fetch() string
}
// 正确:值接收者,mock 可以是值或指针
func (s ServiceImpl) Fetch() string { return "ok" }
// 危险:指针接收者,mock 必须是指针,且被测代码必须传 &mockObj
func (s *ServiceImpl) Fetch() string { return "ok" }
testify/mock 时,若 mock 对象字段含指针(如 db *sql.DB),记得在 SetupTest 中重置,否则测试间共享连接池状态io.Reader)做 mock,尽量用值包装(如 struct{ io.Reader }),避免直接嵌入指针字段type ID int 和 func (id *ID) String() string 看似无害,但会让所有使用 ID 的地方被迫传地址,破坏值语义的可预测性。