根本原因是beego.TestBeegoInit()未触发路由注册,必须通过空白导入import _ "your-module/routers"强制执行routers.init(),否则beego.BeeApp.Handlers.Routes为空导致404;还需正确设置路径参数并用ServeHTTP模拟完整请求链。

beego.TestBeegoInit() 为什么总报 404
根本原因不是路由写错了,而是 beego.TestBeegoInit() 没触发路由注册。Beego 的路由靠 init() 函数自动执行,而测试文件默认不加载未被显式导入的包。
必须在测试文件顶部加空白导入:import _ "your-module/routers"(路径需和 go.mod 中模块名完全一致);否则 beego.BeeApp.Handlers.Routes 始终为空。
- 验证是否成功:加一行
beego.Trace("Routes:", beego.BeeApp.Handlers.Routes),输出非空才说明路由已加载 - 路径参数传错也会失败:推荐用
beego.AppPath或filepath.Join("..", ".."),避免硬写相对路径如"." - 别在
TestXXX函数里调用TestBeegoInit—— 它必须在所有测试开始前完成,建议放在BeforeSuite(Ginkgo)或func TestMain(m *testing.M)中
用 ServeHTTP 模拟请求比 new Controller 更可靠
手动 new UserController 再调 Get(),会跳过中间件、Session、参数绑定、Flash 数据等关键运行时环节,测的不是真实链路。
正确做法是复用 Beego 内置的 Handler 树:beego.BeeApp.Handlers.ServeHTTP(w, req),它完整走通路由匹配 → 中间件 → 控制器执行 → 渲染/响应流程。
-
req, _ := http.NewRequest("POST", "/api/user", strings.NewReader(`{"name":"a"}`))—— 注意构造好 body -
w := httptest.NewRecorder()接收响应,之后可断言w.Code、w.Body.String()、w.Header().Get("Content-Type") - 此方式不启动端口、无网络开销,但要求
TestBeegoInit和路由导入已就绪
Ginkgo + Gomega 是控制器测试的实际标准
原生 testing 包写 Beego 测试容易堆逻辑、难维护,尤其涉及登录态、嵌套请求时状态管理混乱。
Ginkgo 提供 Describe/It 结构,Gomega 提供语义化断言,天然适配 Beego 的 http.Handler 接口。
- 入口文件必须是
*_suite_test.go,含RunSpecs(t, "MyApp Suite") - 每个
It只验证一个行为:比如 “带有效 token 能获取用户”,不要混“token 无效返回 401”进去 - 常用断言:
Expect(w.Code).To(Equal(http.StatusOK))、Expect(w.Body.String()).To(MatchJSON(`{"id":1}`))
POST 表单和 JSON 的 Content-Type 必须匹配
Beego 对不同 Content-Type 的参数解析逻辑完全不同:表单走 c.Input().Get(),JSON 走 c.ParseForm() 或结构体绑定。测试时若不设对头,参数永远拿不到。
- 表单提交:
req, _ := http.NewRequest("POST", "/login", strings.NewReader("username=a&password=b")),再设req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - JSON 提交:
req.Header.Set("Content-Type", "application/json"),body 用json.Marshal构造 - 漏掉
Content-Type或写错(如写成text/json),c.GetString("xxx")会返回空字符串,且无错误提示
最容易被忽略的是路由导入那行空白 import —— 它不报错、不警告,只默默让所有路由失效。只要 beego.BeeApp.Handlers.Routes 是空的,后面所有请求都注定 404。


















