0

0

Golang如何在测试中使用内存数据库

P粉602998670

P粉602998670

发布时间:2026-01-08 15:48:04

|

935人浏览过

|

来源于php中文网

原创

测试不用真实数据库而选内存数据库,因其启动快、无外部依赖、状态易重置,保障测试快速、稳定、可并行;sqlite的:memory:模式最常用,需每个测试用独立*sql.DB实例防污染。

golang如何在测试中使用内存数据库

为什么测试中不用真实数据库而选内存数据库

真实数据库启动慢、依赖外部服务、状态难重置,会导致测试变慢、不稳定、难以并行。内存数据库(如 sqlite:memory: 模式、bbolt 内存模式、或纯内存实现的 go-sqlmock + sqlmock 驱动)能绕过 I/O 和网络,让单元测试真正“快”和“隔离”。

sqlite:memory: 模式做真实 SQL 测试

这是最常用也最贴近生产环境的做法:用真实 SQL 驱动跑在内存里,既验证 SQL 逻辑,又避免磁盘/连接开销。关键点是每个测试必须用独立的 *sql.DB 实例,否则事务和表结构会互相污染。

  • sqlite3.Open("file::memory:?cache=shared") 是基础写法,但注意 cache=shared 可让多个 *sql.DB 共享同一内存数据库(仅限单 goroutine 场景)
  • 更安全的做法是每个测试用独立 :memory: 实例,并在测试开始时执行建表语句(例如用 db.Exec("CREATE TABLE users(...)")
  • 不要复用全局 *sql.DB,否则 TestA 创建的表可能被 TestB 误读——Go 的 testing.T.Parallel() 下尤其危险
func TestUserCreate(t *testing.T) {
	db, err := sql.Open("sqlite3", "file::memory:")
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	_, err = db.Exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`)
	if err != nil {
		t.Fatal(err)
	}

	// 真实业务逻辑调用
	err = CreateUser(db, "alice")
	if err != nil {
		t.Fatal(err)
	}

	var count int
	err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
	if err != nil || count != 1 {
		t.Errorf("expected 1 user, got %d", count)
	}
}

sqlmock 模拟数据库行为(不执行真实 SQL)

适合验证 DAO 层是否发出了预期 SQL,但不关心 SQL 是否真能运行。它不连接任何数据库,纯 mock,因此无法捕获语法错误或约束冲突。

  • 必须用 sqlmock.New() 创建 *sql.DB,且不能传给 sql.Open
  • 每条期望 SQL 都要显式调用 mock.ExpectQuery()mock.ExpectExec(),否则测试会 panic
  • 调用 mock.ExpectationsWereMet() 必须放在 defer 或结尾,否则未触发的期望不会报错
func TestUserCreateWithMock(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	mock.ExpectExec(`INSERT INTO users`).WithArgs("alice").WillReturnResult(sqlmock.NewResult(1, 1))

	err = CreateUser(db, "alice")
	if err != nil {
		t.Fatal(err)
	}

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

常见踩坑:事务没回滚、连接池干扰、驱动注册遗漏

内存数据库不是“自动干净”的魔法盒。很多问题源于 Go 的 database/sql 默认行为和 SQLite 驱动细节。

传媒公司模板(RTCMS)1.0
传媒公司模板(RTCMS)1.0

传媒企业网站系统使用热腾CMS(RTCMS),根据网站板块定制的栏目,如果修改栏目,需要修改模板相应的标签。站点内容均可在后台网站基本设置中添加。全站可生成HTML,安装默认动态浏览。并可以独立设置SEO标题、关键字、描述信息。源码包中带有少量测试数据,安装时可选择演示安装或全新安装。如果全新安装,后台内容充实后,首页才能完全显示出来。(全新安装后可以删除演示数据用到的图片,目录在https://

下载

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

  • SQLite 的 :memory: 数据库在 *sql.DB 关闭后即销毁,但若代码中用了 db.Begin() 却没 tx.Commit()tx.Rollback(),事务会一直挂起,导致后续操作卡住或报 database is locked
  • sql.Open 不建立连接,首次 db.Query 才真正初始化;如果测试中只 sql.Open 但没执行任何语句,db 实际未生效,容易误判“测试通过”
  • 忘记 import _ "github.com/mattn/go-sqlite3" 会导致 sql.Open("sqlite3", ...) 报错 sql: unknown driver "sqlite3"
  • 使用 github.com/glebarez/sqlite(纯 Go 实现)替代 cgo 驱动时,路径协议要写成 sqlite://:memory:,且不支持 cache=shared

最易忽略的是:SQLite 的 :memory: 数据库默认是“连接级私有”,哪怕你用同一个 DSN,两个 sql.Open 返回的 *sql.DB 看不到彼此的表——这不是 bug,是设计。需要共享就得显式加 cache=shared,但要注意它不适用于并发测试。

相关专题

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

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

177

2024.02.23

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

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

226

2024.02.23

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

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

336

2024.02.23

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

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

208

2024.03.05

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

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

388

2024.05.21

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

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

194

2025.06.09

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

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

189

2025.06.10

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

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

191

2025.06.17

Golang 分布式缓存与高可用架构
Golang 分布式缓存与高可用架构

本专题系统讲解 Golang 在分布式缓存与高可用系统中的应用,涵盖缓存设计原理、Redis/Etcd集成、数据一致性与过期策略、分布式锁、缓存穿透/雪崩/击穿解决方案,以及高可用架构设计。通过实战案例,帮助开发者掌握 如何使用 Go 构建稳定、高性能的分布式缓存系统,提升大型系统的响应速度与可靠性。

53

2026.01.09

热门下载

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

精品课程

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

共21课时 | 2.5万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

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

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