0

0

如何使用Golang测试数据库操作_Golang sql包单元测试技巧

P粉602998670

P粉602998670

发布时间:2026-01-20 12:00:12

|

287人浏览过

|

来源于php中文网

原创

应根据测试目标选择 sqlmock(验证 SQL 逻辑)或 SQLite 内存模式(验证端到端行为):前者纯内存模拟、速度快、需设 ExpectQuery/Exec 并调用 ExpectationsWereMet;后者真实执行、需手动建表、适合测迁移、映射和事务。

如何使用golang测试数据库操作_golang sql包单元测试技巧

Go 的 database/sql 本身不提供内存数据库或自动 mock 能力,直接测真实数据库容易污染、慢、不可靠;真正可行的方案是用 sqlmock 模拟驱动行为,或用轻量级真实 DB(如 SQLite 内存模式)做集成验证——二者适用场景不同,选错就卡在 CI 或测试稳定性上。

用 sqlmock 拦截并断言 SQL 执行逻辑

sqlmock 是最常用的测试工具,它替换掉 sql.DB 的底层驱动,让你能精确控制返回结果、检查 SQL 是否被调用、参数是否匹配。它不执行真实 SQL,纯内存模拟,速度快、隔离性好。

常见错误现象:忘记调用 mock.ExpectQuery()mock.ExpectExec() 就执行语句,导致 panic 报 “there is no expectation for…”;或用了 QueryRow().Scan() 却只设了 ExpectQuery(),漏掉 WillReturnRows()

  • 必须先通过 sqlmock.New() 创建 mock DB,再传给待测函数(不能直接在函数里 sql.Open("postgres", ...)
  • 查询类操作用 mock.ExpectQuery("SELECT").WithArgs(...).WillReturnRows(...)
  • 写入类操作用 mock.ExpectExec("INSERT").WithArgs(...).WillReturnResult(sqlmock.NewResult(1, 1))
  • 测试结束后务必调用 mock.ExpectationsWereMet(),否则未触发的 expect 不报错
func TestGetUser(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	mock.ExpectQuery(`^SELECT id, name FROM users WHERE id = \?$`).WithArgs(123).
		WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(123, "alice"))

	user, err := GetUser(db, 123)
	if err != nil {
		t.Fatal(err)
	}
	if user.Name != "alice" {
		t.Error("expected alice")
	}

	if err := mock.ExpectationsWereMet(); err != nil {
		t.Error(err)
	}
}

用 SQLite 内存模式做端到端行为验证

当你要验证 migration 是否生效、GORM struct tag 是否正确映射、或事务嵌套逻辑时,sqlmock 太薄——它不解析 SQL,也不校验字段类型。这时用 sqlite3:memory: 模式更合适:真实执行 SQL,但进程退出即销毁,无副作用。

立即学习go语言免费学习笔记(深入)”;

使用场景:测试 DAO 层完整流程、验证外键/索引/默认值、调试“为什么 Scan() 总是 nil”这类底层行为问题。

Frase
Frase

Frase是一款出色的长篇 AI 写作工具,快速创建seo优化的内容。

下载
  • 注册驱动:import _ "github.com/mattn/go-sqlite3"
  • 打开连接:db, err := sql.Open("sqlite3", ":memory:")
  • 必须手动建表(CREATE TABLE),sqlmock 不需要这步,但 SQLite 需要
  • 注意 SQLite 的类型亲和性(比如 INT 列也能存字符串),和 PostgreSQL/MySQL 行为不一致,别拿它测精度敏感逻辑

避免在测试中硬编码数据库连接字符串

本地跑得通、CI 失败,十有八九是测试代码里写了 sql.Open("pgx", "host=localhost...")。这种写法让测试强依赖外部服务状态,且无法统一管理凭证或超时。

正确做法是把 *sql.DB 作为参数注入,由测试用例决定用 mock 还是真实 DB:

  • DAO 函数签名应为 func CreateUser(db *sql.DB, u User) error,而非内部自己 sql.Open
  • 测试时统一用 testDB := setupTestDB(t) 工厂函数,内部根据环境变量切换 mock / sqlite / pg
  • 若用 GORM,记得在测试中禁用日志:gorm.Config{Logger: logger.Default.LogMode(logger.Silent)},否则大量输出干扰断言

事务测试必须显式 Commit/Rollback

很多人写事务测试时只调 db.Begin(),然后执行操作,却忘了 tx.Commit()tx.Rollback()。这会导致连接泄漏、后续测试失败,甚至 mock 报 “transaction has already been committed”。

尤其注意嵌套事务(如使用 sql.Tx 传参的 service 层):

  • 每个 Begin() 必须配对 Commit()Rollback(),哪怕测试失败也要 defer 确保执行
  • mock.ExpectBegin() + mock.ExpectCommit() 可验证事务边界是否被正确开启/提交
  • SQLite 内存模式中,事务行为接近真实 DB,适合验证 Savepoint 和回滚粒度

最难的不是写测试,而是判断该用 mock 还是真实 DB——查 SQL 语法是否拼错?用 sqlmock;查 JOIN 结果字段顺序是否错乱?用 SQLite;查分布式事务下锁等待是否触发超时?那就得上真实的 PostgreSQL 并配好 pg_ctl。别让一种方案包打天下

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

179

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

392

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

191

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

192

2025.06.17

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

3

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 801人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号