在 go 单元测试中,若为 `io.writer` 接口实现值接收者 mock,会导致写入操作作用于副本而非原实例,从而断言失败;必须使用指针接收者并传入指针实例,才能让 `write()` 修改原始数据。
Go 的函数参数和方法调用始终是按值传递——即使传入的是结构体变量,实际传递的也是其副本。因此,当 WriterMock 的 Write 方法使用值接收者(func (w WriterMock) Write(...))时,每次调用都会操作该结构体的一个独立拷贝,对 w.data 的修改不会反映到原始 WriterMock 实例上,最终导致测试断言 string(fileLogger.File.(WriterMock).data) 为空字符串而失败。
要解决此问题,需同时满足两个条件:
✅ 正确实现如下:
// filelogger_test.go
type WriterMock struct {
data []byte
}
// ✅ 关键:使用指针接收者
func (w *WriterMock) Write(b []byte) (n int, err error) {
w.data = append(w.data, b...) // 修改原始实例的 data 字段
return len(b), nil // 注意:应返回 len(b),非 len(w.data)
}
func NewMockedFileLogger() *FileLogger {
writer := &WriterMock{} // ✅ 创建指针实例
return &FileLogger{File: writer}
}
func TestLog(t *testing.T) {
fileLogger := NewMockedFileLogger()
fileLogger.Log("Hello World!")
// ✅ 类型断言也需使用 *WriterMock
assert.Equal(t, "Hello World!\n", string(fileLogger.File.(*WriterMock).data))
}⚠️ 补充注意事项:

总结:Go 接口实现的本质是方法集匹配,而方法集取决于接收者类型。测试中模拟可变状态的接口(如 io.Writer、io.Reader)时,务必统一使用指针接收者 + 指针实例,避免“看似调用成功,实则修改无效”的陷阱。