使用DoAndReturn为Go接口参数赋值时遇nil问题求助
问题分析与解决
核心原因
你在DoAndReturn的闭包里直接给value赋值,这是值传递的问题——闭包里的value是原参数的副本,修改副本不会影响外部传入的变量。Go里的interface{}参数传递也是值拷贝,要修改原对象必须操作其底层指针。
另外,你的mock还存在类型不匹配问题:预期接收&models.Badge{}类型,但赋值的是[]*models.Thing,这会导致类型断言失败,即便解决了传递问题也无法正确赋值。
修正步骤
- 通过指针修改原对象:在闭包里用类型断言获取目标指针,修改指针指向的内容,这样外部传入的变量才会同步更新
- 保证类型匹配:mock的赋值类型要和预期的参数类型完全一致
修正后的测试代码(匹配*models.Badge类型)
s.mockRedisClient.EXPECT().GetStruct(gomock.Any(), cache.BadgesAll, gomock.AssignableToTypeOf(&models.Badge{})).DoAndReturn(func(ctx context.Context, key cache.Key, value any) (*time.Duration, error) { // 类型断言获取目标指针 badgePtr, ok := value.(*models.Badge) if !ok { return nil, fmt.Errorf("invalid value type") } // 修改指针指向的内容,外部变量会同步更新 *badgePtr = models.Badge{ ID: 1, Name: "Test Badge", // 填充测试所需的其他字段 } duration := time.Minute * 1 return &duration, nil })
如果实际需求是返回[]*models.Thing,则调整mock的参数预期:
s.mockRedisClient.EXPECT().GetStruct(gomock.Any(), cache.BadgesAll, gomock.AssignableToTypeOf(&[]*models.Thing{})).DoAndReturn(func(ctx context.Context, key cache.Key, value any) (*time.Duration, error) { thingsPtr, ok := value.(*[]*models.Thing) if !ok { return nil, fmt.Errorf("invalid value type") } *thingsPtr = []*models.Thing{{ID: 1}} duration := time.Minute * 1 return &duration, nil })
关键知识点
- Go中所有参数都是值传递,包括
interface{}——传递的是接口值的副本,要修改原对象必须操作其内部的指针 - gomock的
DoAndReturn闭包参数是原调用参数的副本,直接赋值不会影响外部变量 - 必须保证mock的参数类型和被测代码传入的类型完全匹配,否则类型断言失败,赋值无效
内容的提问来源于stack exchange,提问作者Liam Fell
相关产品推荐
相关产品推荐

