
Echo 测试时 c.Get("user") 返回 nil,是因为未手动触发 JWT 中间件;需显式调用中间件函数链(middleware.JWT(...)(handler)(c)),而非仅注册中间件,才能确保 c.Get("user") 在测试上下文中被正确赋值。
echo 测试时 `c.get("user")` 返回 nil,是因为未手动触发 jwt 中间件;需显式调用中间件函数链(`middleware.jwt(...)(handler)(c)`),而非仅注册中间件,才能确保 `c.get("user")` 在测试上下文中被正确赋值。
在 Echo 框架中进行单元测试时,一个常见误区是:仅创建 echo.Echo 实例并调用 Use() 注册中间件,并不能使中间件在 e.NewContext() 创建的测试上下文中生效。这是因为 Use() 仅影响后续通过 e.Start() 或 e.ServeHTTP() 启动的 HTTP 服务流程,而纯内存中的 Context 不会自动执行中间件链——你必须手动构造并调用中间件装饰后的处理器。
✅ 正确做法:显式调用中间件链
JWT 中间件(如 middleware.JWTWithConfig)返回的是一个 echo.MiddlewareFunc 类型函数,其签名本质为:
func(echo.HandlerFunc) echo.HandlerFunc
即:它接收一个原始 handler,返回一个「被 JWT 验证逻辑包裹后」的新 handler。因此,在测试中,你需要:
- 构造 JWT 中间件(传入正确
SigningKey等配置); - 将待测 handler(如
Logout(db, r))作为参数传入该中间件; - 再将得到的装饰后 handler 应用于测试
Context。
以下是修正后的测试代码片段(关键部分已高亮):
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
Convey("with a valid token, you should get a success msg and be logged out", func() {
e := echo.New()
req, err := http.NewRequest(echo.POST, "/auth/logout", strings.NewReader(""))
So(err, ShouldBeNil)
// ✅ 关键:设置 Authorization Header
req.Header.Set(echo.HeaderAuthorization, fmt.Sprintf("Bearer %s", Token))
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
// ✅ 关键:手动执行 JWT 中间件 + handler 组合
jwtMiddleware := middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte("secret"), // 必须与生产环境一致
// 注意:TokenLookup 默认为 "header:Authorization",无需额外设为 "query:user"
// 若使用 query 参数传 token,请显式指定 TokenLookup: "query:token"
})
// 执行链:jwtMiddleware(handler)(c)
handler := Logout(db, Models.Redis)
jwtMiddleware(handler)(c)
// 断言响应
body := GetJsonBody(rec.Body.String())
So(rec.Code, ShouldEqual, 200)
So(body.Path("error").Data(), ShouldBeNil)
So(body.Path("msg").Data().(string), ShouldEqual, "Logged Out")
So(body.Path("data.user.password").Data().(string), ShouldEqual, "")
So(body.Path("data.user.token").Data(), ShouldBeNil)
})
⚠️ 注意事项
-
TokenLookup配置需匹配实际请求方式:默认为"header:Authorization",若你在生产中用?user=xxx传递 token,则应设为"query:user";但更推荐遵循标准 Bearer 格式(即Authorization: Bearer),避免歧义。 -
密钥一致性:测试中
SigningKey必须与生成 token 时使用的密钥完全一致,否则验证失败,c.Get("user")始终为nil。 -
不要依赖
e.Use():e.Use()仅对e.ServeHTTP()有效,在纯 Context 测试中无效。 -
中间件顺序无关(单次测试):因你手动调用,无需关心
Use()的注册顺序;但若测试多个中间件(如 JWT + CORS + Logger),可按需嵌套:mwA(mwB(handler))(c)。 -
c.Get("user")类型断言安全:在 handler 中建议先判空再断言,例如:if userI := c.Get("user"); userI != nil { if token, ok := userI.(*jwt.Token); ok { // 安全使用 } }
✅ 总结
Echo 的中间件本质是函数式装饰器。测试时没有“运行服务器”这一环节,因此所有中间件逻辑必须显式触发。牢记三段式调用模式:
middleware.ConfiguredMW(
yourHandler
)(testContext)
这是 Echo 单元测试的核心范式,适用于 JWT、BasicAuth、CORS、Recover 等所有官方及自定义中间件。掌握此模式,即可精准模拟真实请求生命周期,让 c.Get()、c.Request().Context()、c.Response() 等行为与线上环境完全一致。










