You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中如何将Protobuf对象传入sqlmock.AddRow?测试遇字段为空

问题解决:SQLMock测试GORM代码时user.name为nil的修复方案

核心问题分析

  • 结构体字段不可导出:Go语言中首字母小写的字段(如user.name)属于包私有成员,GORM无法通过反射机制为其赋值,导致从数据库查询后该字段始终为nil。
  • SQLMock列与GORM映射不匹配:你定义的SQLMock行列名(user_id、user_name)未覆盖GORM查询所需的关键字段(如uuid),且列名与结构体字段的映射关系不对。
  • 误解Protobuf传入方式:AddRow不需要直接传入Protobuf对象,只需传入数据库原始数据,Protobuf转换由结构体的Protobuf()方法处理。

具体修复步骤

1. 修正User结构体的字段可访问性

确保usermodels.User中用于存储用户名和用户ID的字段是首字母大写的可导出字段,并通过GORM标签明确对应数据库列:

package usermodels

type User struct {
    UUID string `gorm:"column:uuid;primaryKey"` // 对应数据库uuid列
    Name string `gorm:"column:user_name"`       // 对应数据库user_name列
    // 其他字段...
}

// 保持你的Protobuf()方法不变
func (u *User) Protobuf() *yourpb.User {
    // 结构体转Protobuf逻辑
}

同时修改原业务代码中的打印语句:

fmt.Printf("user name %+v", user.Name)

2. 对齐SQLMock的行数据与GORM查询

GORM执行db.First()时会查询结构体所有可导出字段对应的列,因此SQLMock的Rows必须包含这些列。至少需要包含查询条件用到的uuid和要打印的user_name:

rows := sqlmock.NewRows([]string{"uuid", "user_name"}).
    AddRow("user-fd3746c8-d32f-4fb8-8f6a-b6d72dcf2969", "John")

同时修正ExpectQuery中的SQL语句,确保与GORM生成的PostgreSQL语法完全匹配(注意列名的引号):

mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "users" WHERE "uuid" = $1`)).
    WithArgs("user-fd3746c8-d32f-4fb8-8f6a-b6d72dcf2969").
    WillReturnRows(rows)

3. 验证测试逻辑

在测试代码末尾添加SQLMock的预期验证,确保所有SQL操作都已执行:

if err := mock.ExpectationsWereMet(); err != nil {
    t.Errorf("unfulfilled SQL expectations: %s", err)
}

完整修正后的测试代码

func TestEnrollCourse(t *testing.T){
    db, mock, err := sqlmock.New()
    if err != nil {
        t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
    }
    defer db.Close()

    rows := sqlmock.NewRows([]string{"uuid", "user_name"}).
        AddRow("user-fd3746c8-d32f-4fb8-8f6a-b6d72dcf2969", "John")
    
    mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "users" WHERE "uuid" = $1`)).
        WithArgs("user-fd3746c8-d32f-4fb8-8f6a-b6d72dcf2969").
        WillReturnRows(rows)
    
    gdb, err := gorm.Open(postgres.New(postgres.Config{
        Conn: db,
    }), &gorm.Config{})
    if err != nil {
        t.Fatalf("failed to initialize GORM DB: %v", err)
    }

    err = enrollCourse(gdb, "user-fd3746c8-d32f-4fb8-8f6a-b6d72dcf2969", "english_course")
    if err != nil {
        t.Fatalf("enrollCourse execution failed: %v", err)
    }

    if err := mock.ExpectationsWereMet(); err != nil {
        t.Errorf("unfulfilled SQL expectations: %s", err)
    }
}

内容的提问来源于stack exchange,提问作者Panduranga Rao Sadhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:10:45