Revel测试中不能直接用生产数据库造数据,因为tests目录下测试默认运行于独立内存环境、不连接真实数据库,若调用models.CreateUser()且未初始化DB连接,会panic报“sql: database is closed”;正确做法是在Before()中显式创建专用测试DB连接(如sqlite in-memory或临时Docker实例),并通过HTTP请求构造和清理数据以覆盖完整中间件链。

Revel测试中为什么不能直接用生产数据库造数据
Revel的tests目录下运行的测试默认走独立内存环境,不连接真实数据库。如果你在TestThatIndexPageWorks里调用models.CreateUser()却没初始化DB连接,会直接panic:「sql: database is closed」。这不是代码写错了,而是Revel测试套件默认禁用持久层——它假设你用的是内存Mock或预置fixture数据。
用TestSuite.Before()注入测试专用DB连接
Revel的rev.TestSuite支持在每个测试方法执行前重置状态,Before()是唯一安全的DB初始化入口。必须显式创建新连接,且不能复用app.Init()里的全局DB实例(它可能被其他测试污染)。
- 在
Before()里用sql.Open("sqlite3", ":memory:")建一个干净内存库(适合轻量模型) - 若需MySQL/PostgreSQL,改用临时docker容器或
testdb.NewTempDB()类工具,避免端口冲突 - 务必在
After()里调用db.Close(),否则并发测试时会报「too many connections」
API测试数据优先走HTTP请求构造,而非模型层
Revel测试的核心逻辑是模拟真实HTTP流量,所以准备数据最自然的方式是发POST请求,而不是调用models.User.Save()。比如测试借阅接口前,先用t.PostForm("/api/users", url.Values{"name": {"testuser"}})注册用户。这样能同时验证路由、参数解析、校验逻辑是否正常,避免绕过中间件导致漏测。
常见错误是把测试写成「先模型插入、再HTTP调用」,结果SessionFilter或ValidationFilter没触发,看似通过实则没测到关键路径。
测试数据清理必须匹配构造方式
用HTTP构造的数据,必须用HTTP清理:调用t.Delete("/api/users/123"),而不是db.Exec("DELETE FROM users")。原因很实际——Revel的Before()里如果手动清库,会把其他测试刚插的数据也干掉;而HTTP DELETE会走完整过滤器链,触发AuthFilter鉴权和InterceptorFilter事务回滚,这才是真实场景。
真正容易被忽略的是时间敏感型字段:比如借阅记录带created_at,若测试中硬编码时间戳,跨时区CI机器上会断言失败。应该让API返回生成的时间,或用time.Now().UTC().Truncate(time.Second)对齐精度。











