本文介绍在 Go 单元测试中,利用 redigomock 模拟并验证 Redis MULTI/EXEC 事务流程的正确写法,包括命令链式调用、预期响应断言及常见陷阱规避。
本文介绍在 go 单元测试中,利用 redigomock 模拟并验证 redis `multi`/`exec` 事务流程的正确写法,包括命令链式调用、预期响应断言及常见陷阱规避。
在 Go 生态中,redigomock 是一个轻量且兼容 github.com/gomodule/redigo/redis 的 Redis 客户端模拟库,广泛用于无依赖单元测试。测试 Redis 事务(即 MULTI → 多条命令 → EXEC)时,关键在于:确保所有命令被正确入队,并由 EXEC 触发执行与结果聚合。
redigomock 并不真正执行 Redis 命令逻辑,而是通过显式声明(.Command())和断言(.Expect())构建行为契约。对事务的支持是内建的——只要按 Redis 协议顺序调用 MULTI、中间命令、EXEC,mock 连接会自动将中间命令暂存至队列,并在 EXEC 调用时返回预设的响应切片。
以下是一个完整、可运行的测试示例(基于 go-check,但适配 testify/assert 或标准 testing 同样简单):
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
func TestRedisTransactionWithRedigomock(t *testing.T) {
conn := redigomock.NewConn()
// 模拟事务流程
cmdMulti := conn.Command("MULTI")
cmdSet := conn.Command("SET", "person-123", "123456")
cmdExpire := conn.Command("EXPIRE", "person-123", "1000")
cmdExec := conn.Command("EXEC").Expect([]interface{}{"OK", int64(1)})
// 执行业务逻辑(假设封装在某个函数中)
// e.g., err := doPersonUpdate(conn, "person-123", 123456, 1000)
// 断言每条命令均被调用一次
assert.Equal(t, 1, conn.Stats(cmdMulti))
assert.Equal(t, 1, conn.Stats(cmdSet))
assert.Equal(t, 1, conn.Stats(cmdExpire))
assert.Equal(t, 1, conn.Stats(cmdExec))
}
⚠️ 重要注意事项:
- MULTI 和 EXEC 必须成对出现;若遗漏 EXEC 或中间命令拼写错误(如 "SETT"),redigomock 默认不会报错(早期版本甚至静默忽略),导致测试“假通过”。建议升级至 v1.1.0+(含 PR #21)以启用未匹配命令的 panic 提示。
- .Expect() 仅作用于 EXEC 命令,其参数为 []interface{},需严格匹配实际返回的命令结果顺序与类型(如 SET 返回 "OK",EXPIRE 返回 int64(1) 表示成功)。
- 不支持 DISCARD 或 WATCH 等高级事务特性;如需测试乐观锁逻辑,应结合真实 Redis 实例或改用更高级 mock 方案(如 miniredis)。
总结:使用 redigomock 测试 Redis 事务的核心是显式建模命令序列 + 精确断言 EXEC 响应。保持命令字符串大小写、参数顺序与生产代码一致,并善用 conn.Stats() 验证调用次数,即可高效覆盖事务逻辑,无需启动真实 Redis 服务。










