Go单元测试遇user_id主键冲突,如何设置GetCurrentUserID默认值?
解决Go单元测试中user_id主键冲突及控制GetCurrentUserID返回值的问题
核心思路
要在单元测试中让GetCurrentUserID稳定返回1,核心是隔离外部依赖,不让它读取真实用户上下文(比如请求中的用户ID),而是返回预设的固定值。这里提供两种实用方案:
方案一:依赖注入(推荐,代码更易维护)
修改业务代码,将GetCurrentUserID作为依赖传入函数,而非直接调用全局函数:
1. 调整业务代码
// 定义获取用户ID的函数类型 type UserIDGetter func() int // 修改ToggleTrackToFavourite,接收UserIDGetter作为参数 func ToggleTrackToFavourite(trackID int, getUserID UserIDGetter) error { userID := getUserID() // 原有的收藏/取消收藏逻辑... } // 生产环境用的GetCurrentUserID函数 func GetCurrentUserID() int { // 从请求上下文或其他渠道获取真实用户ID return realUserID }
2. 编写单元测试
测试时传入返回固定值1的匿名函数,确保每次调用都拿到相同的user_id:
func TestToggleTrackToFavourite(t *testing.T) { // 测试收藏逻辑 t.Run("add track to favourite", func(t *testing.T) { err := ToggleTrackToFavourite(123, func() int { return 1 }) if err != nil { t.Fatalf("expected no error, got %v", err) } // 验证数据库中是否存在user_id=1、track_id=123的记录 }) // 测试取消收藏逻辑 t.Run("remove track from favourite", func(t *testing.T) { // 先插入一条user_id=1、track_id=123的测试数据 // 调用ToggleTrackToFavourite执行取消操作 err := ToggleTrackToFavourite(123, func() int { return 1 }) if err != nil { t.Fatalf("expected no error, got %v", err) } // 验证数据库中该记录已被删除 }) }
方案二:Mock全局依赖(适合无法修改业务代码的场景)
如果不能改动原有业务代码,可以用Mock库(比如testify/mock)替换全局的用户服务依赖:
1. 定义接口与全局依赖
type UserService interface { GetCurrentUserID() int } // 生产环境实现 type RealUserService struct{} func (r *RealUserService) GetCurrentUserID() int { return realUserID } // 全局依赖,生产环境赋值为RealUserService var userService UserService = &RealUserService{} // 原业务函数依赖全局userService func ToggleTrackToFavourite(trackID int) error { userID := userService.GetCurrentUserID() // 原有收藏/取消收藏逻辑... }
2. 编写测试用Mock实现
import "github.com/stretchr/testify/mock" type MockUserService struct { mock.Mock } func (m *MockUserService) GetCurrentUserID() int { args := m.Called() return args.Int(0) } func TestToggleTrackToFavourite(t *testing.T) { // 替换全局依赖为Mock实例 mockUserSvc := new(MockUserService) userService = mockUserSvc // 设置Mock返回固定值1 mockUserSvc.On("GetCurrentUserID").Return(1) // 执行测试 err := ToggleTrackToFavourite(123) if err != nil { t.Fatal(err) } // 验证Mock方法被正确调用 mockUserSvc.AssertExpectations(t) }
额外解决主键冲突的注意事项
- 每次测试前清空测试数据库的收藏表,或使用事务回滚,避免前一次测试的数据残留导致冲突。
- 确保测试用例之间完全独立,不依赖其他测试的执行顺序。
内容的提问来源于stack exchange,提问作者Galaxy Mail
相关产品推荐
相关产品推荐

