tests/目录必须存在且不可重命名,需与app/、conf/平级;apptest.go为唯一入口,TestMain中须调用revel.Init("TEST","tests",".")初始化BuiltApp;控制器实例必须由TestSuite.Controller()构造,且conf/routes中必须配置GET /@tests Tests.Index路由。

revel init 生成的 tests/ 目录必须存在且不可重命名
Revel 的测试环境不是靠 go test 自动发现的,而是强依赖项目结构。运行 revel init myapp 后,框架会在项目根目录下自动生成 tests/ 目录,并内置 apptest.go —— 这是官方 Test Runner 唯一识别的入口文件。如果你删掉它、改名、或把测试文件挪到 test/ 或 internal/test 下,Test Runner 就完全找不到用例,页面上也不会列出任何可执行项。
常见错误现象:revel run myapp 启动后打开 /@tests 页面,显示空白或只有「No tests found」;本地执行 go test ./tests 报错 no buildable Go source files。
-
tests/必须是小写,且与app/、conf/平级 -
apptest.go文件名不能改成main_test.go或其他名字,它内部调用了revel.TestSuite初始化逻辑 - 新增测试文件(如
user_test.go)必须放在tests/下,且包声明为package tests,不能是package main或package user
revel.BuiltApp 必须在 TestMain 中初始化,否则 TestSuite 返回 nil
所有控制器单元测试都依赖 revel.BuiltApp 提供的完整运行时上下文。这个变量不是自动加载的,必须显式调用 revel.Init() 初始化,否则 &revel.TestSuite{App: revel.BuiltApp} 里的 App 是 nil,后续 testSuite.Controller(&MyController{}) 会直接 panic。
正确做法是在 tests/apptest.go 里补全 TestMain 函数:
func TestMain(m *testing.M) {
revel.Init("TEST", "tests", ".")
os.Exit(m.Run())
}
注意三个参数:"TEST" 是运行模式(对应 conf/app.conf 中的 [TEST] 段),"tests" 是应用路径(必须和目录名一致),"." 是相对路径前缀。漏掉任意一个,revel.BuiltApp 都不会被赋值。
- 跳过
TestMain或只写revel.Init()不传参 →testSuite.Controller()返回nil,测试一跑就 panic - 模式名写成
"dev"但conf/app.conf里没定义[dev]段 → 初始化失败,日志报no app config found for mode 'dev' - 第二个参数误写为
"./tests"或"test"→ 路径解析失败,revel.BuiltApp仍为 nil
测试文件里不能 import 主应用的 controllers 包直引用
Revel 测试要求控制器实例必须由 TestSuite.Controller() 构造,而不是 new(MyController) 或 &MyController{}。但很多开发者会先在 tests/ 里 import myapp/app/controllers,再手动 new —— 这会导致 *revel.Controller 字段未初始化,调用任何方法(比如 c.RenderJSON())都会触发 nil pointer dereference。
真正安全的做法是:在测试函数内,用 testSuite.Controller(&controllers.MyController{}) 获取实例,然后通过类型断言或字段赋值来设置依赖:
func TestMyController_GetData(t *testing.T) {
testSuite := &revel.TestSuite{App: revel.BuiltApp}
controller := testSuite.Controller(&controllers.MyController{}).(*controllers.MyController)
controller.Params.Route.Add("id", "123")
controller.Request.Header.Set("Content-Type", "application/json")
// ...
}
- 不要在文件顶部 import
myapp/app/controllers后直接var c = &controllers.MyController{} -
TestSuite.Controller()返回的是interface{},必须显式转成具体控制器类型才能访问方法 - 若控制器嵌套了自定义字段(如
DB *gorm.DB),需在测试中手动赋值,TestSuite 不会自动注入
@tests 页面打不开或报 404,大概率是路由没启用
Revel 的 Test Runner 是一个内置 HTTP handler,不是独立服务。它只在开发模式(run)下注册路由,且默认绑定在 /@tests。如果启动后访问该路径返回 404,说明框架没加载测试模块 —— 最常见的原因是 conf/routes 里缺少对应配置。
检查 conf/routes 是否包含这一行:
GET /@tests Tests.Index
如果没有,手动加上。这行路由告诉 Revel:当请求 /@tests 时,交由 tests.Tests 控制器处理。它不是可选功能,而是 Test Runner 正常工作的前提。
- 删掉这行路由 → 页面 404,但控制台无报错,容易误判为端口或防火墙问题
- 把路径改成
/test或加前缀 → Test Runner 内部硬编码了资源路径,前端 JS 会加载失败 - 在 production 模式下运行
revel run -m prod→/@tests默认被禁用,仅开发模式可用
测试环境真正难的不是搭起来,而是每个环节都卡在“看起来正常但实际失效”的状态:目录对了但模式名错、TestMain 存在但参数少一个、路由写了但没 reload —— 这些地方不报红,只让测试静默失败。











