本文详解 go 单元测试中因 `io.writer` 接口实现不当导致状态未更新的问题,核心在于:必须为模

在 Go 中,io.Writer 接口要求实现 Write([]byte) (int, error) 方法。但接口是否能被满足,不仅取决于方法签名,还取决于接收器类型。当你的 WriterMock 使用值接收器(func (w WriterMock) Write(...))时,每次调用 Write 都会操作 w 的一个独立副本,因此对 w.data 的修改不会反映到原始变量上——这正是测试失败的根本原因:fileLogger.File.(WriterMock).data 始终为空切片。
✅ 正确做法是:统一使用指针接收器,并确保传入 FileLogger 的是 *WriterMock 实例:
// 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) {
logger := NewMockedFileLogger()
logger.Log("Hello World!")
// ✅ 类型断言也需匹配:*WriterMock
assert.Equal(t, "Hello World!\n", string(logger.File.(*WriterMock).data))
}⚠️ 注意事项:
总结:Go 的值语义决定了只有指针接收器才能修改原始结构体状态。在测试中模拟接口行为时,务必检查接收器类型与实例传递方式的一致性——这是编写可靠单元测试的基础前提。