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

使用go-sqlmock测试时无法自定义INSERT数据的问题

解决GORM INSERT测试中字段不匹配及自定义数据插入问题

核心问题分析

从报错信息可定位两个关键问题:

  1. SQL预期不匹配:GORM默认自动维护created_at、updated_at、deleted_at字段(时间追踪+软删除特性),实际执行的INSERT语句包含这些字段,但你的sqlmock预期仅匹配name和description,导致匹配失败触发事务回滚。
  2. 自定义数据未传入:测试代码中注释了请求Body,POST请求未携带自定义的name和description,最终插入空值。

具体修复步骤

1. 修正sqlmock的INSERT预期

调整预期SQL的正则匹配规则,适配GORM自动生成的字段,同时用sqlmock.AnyArg()匹配动态生成的时间值:

// 替换原INSERT预期代码
mock.ExpectBegin()
// 匹配包含所有字段的INSERT语句,注意转义反引号和括号
mock.ExpectExec(`INSERT INTO \`projects\` \(`created_at`,`updated_at`,`deleted_at`,`name`,`description`\)`).
    // 前三个参数为GORM自动生成的动态值,用AnyArg()匹配;后两个为自定义数据
    WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), "测试项目", "测试描述").
    WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit()

2. 启用自定义请求数据

取消测试中请求Body的注释,确保POST请求携带合法JSON数据:

apitest.New().
    Debug().
    Handler(r).
    Post("/project").
    // 传入自定义的项目数据
    Body(`{"name": "测试项目", "description": "测试描述"}`).
    Expect(t).
    Status(http.StatusOK).
    End()

3. 完善HTTP请求处理逻辑

原CreateProject是结构体方法,需补充HTTP Handler完成请求体到Project实例的绑定,否则无法获取请求中的自定义数据:

// 新增HTTP Handler函数
func CreateProjectHandler(db *gorm.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var project Project
        // 解析请求体到Project结构体
        if err := json.NewDecoder(r.Body).Decode(&project); err != nil {
            w.WriteHeader(http.StatusBadRequest)
            json.NewEncoder(w).Encode(map[string]string{"error": "请求参数错误"})
            return
        }
        // 调用CreateProject方法执行插入
        if errResp := project.CreateProject(db); errResp != nil {
            w.WriteHeader(http.StatusInternalServerError)
            json.NewEncoder(w).Encode(errResp)
            return
        }
        // 返回成功响应
        w.WriteHeader(http.StatusOK)
        json.NewEncoder(w).Encode(project)
    }
}

// 测试中注册路由时使用该Handler
r.HandleFunc("/project", CreateProjectHandler(gormDB)).Methods("POST")

额外说明

  • 若不需要GORM的时间追踪和软删除特性,可在初始化时关闭:
    gormDB, err := gorm.Open(mysql.New(mysql.Config{
        Conn: db,
        SkipInitializeWithVersion: true,
    }), &gorm.Config{
        // 关闭自动时间戳
        DisableAutomaticTimeStamp: true,
        // 关闭软删除
        DisableForeignKeyConstraintWhenMigrating: true,
    })
    
  • 测试中mock.ExpectationsWereMet()应放在测试流程最后(如End()之后),提前调用会干扰后续数据库操作的预期验证。

内容的提问来源于stack exchange,提问作者JonB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:20:32