如何基于公开API测试Go的alexedwards/scs会话功能?
测试alexedwards/scs会话功能的最简方法
问题背景
想要为alexedwards/scs v2编写简单测试,验证会话存取值的一致性,但遇到了以下问题:
第一次编写的测试代码运行时触发panic:scs: no session data in context:
func TestScs_SetGetIsSame1(t *testing.T) { sessionManager := scs.New() req := httptest.NewRequest("GET", "/", nil) key := "boolean" expected := false sessionManager.Put(req.Context(), key, expected) actual := sessionManager.GetBool(req.Context(), key) assert.Equal(t, expected, actual) }
尝试用httptest.Server编写测试时,误用了sessionManager.LoadAndSave(ts)(httptest.Server并非http.Handler类型),代码如下:
func TestScs_SetGetIsSame2(t *testing.T) { sessionManager := scs.New() ts := httptest.NewServer((http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") expected := true sessionManager.Put(r.Context(), "key", expected) actual := sessionManager.GetBool(r.Context(), "key") assert.Equal(t, expected, actual) }))) defer ts.Close() res, err := http.Get(ts.URL) if err != nil { log.Fatal(err) } greeting, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) } fmt.Printf("%s", greeting) sessionManager.LoadAndSave(ts) }
另外注意到scs仓库的测试使用了私有函数addSessionDataToContext,但不想依赖私有实现,因此询问Go中测试会话功能的最佳最简方法。
最简测试方案
方案1:手动初始化会话上下文
scs要求会话数据必须先加载到请求上下文才能读写,直接调用Put会panic是因为上下文没有会话数据。可以使用公开的Load方法手动加载会话到上下文,无需依赖私有函数:
func TestScs_SetGet(t *testing.T) { sm := scs.New() req := httptest.NewRequest("GET", "/", nil) // 手动加载会话到请求上下文,空字符串表示新建会话 ctx, err := sm.Load(req.Context(), "") if err != nil { t.Fatal(err) } key := "boolean" expected := false sm.Put(ctx, key, expected) actual := sm.GetBool(ctx, key) assert.Equal(t, expected, actual) }
方案2:模拟真实HTTP请求流程(贴近实际场景)
如果要测试完整的中间件流程,可使用sessionManager.LoadAndSave作为中间件包裹业务handler,再用httptest.NewRequest和httptest.ResponseRecorder模拟请求,无需启动真实HTTP服务器:
func TestScs_RealFlow(t *testing.T) { sm := scs.New() // 定义测试handler,在会话中存值并验证一致性 testHandler := sm.LoadAndSave(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { expected := true sm.Put(r.Context(), "key", expected) actual := sm.GetBool(r.Context(), "key") assert.Equal(t, expected, actual) w.WriteHeader(http.StatusOK) })) req := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() // 让handler处理模拟请求 testHandler.ServeHTTP(w, req) // 可选:验证响应状态是否符合预期 assert.Equal(t, http.StatusOK, w.Code) }
关键说明
- 方案1适合单元测试,直接测试会话存取值逻辑,跳过HTTP中间件流程,执行速度更快。
- 方案2更贴近真实运行场景,测试中间件是否正确将会话上下文注入请求,适合集成测试。
- 不要直接向
LoadAndSave传入httptest.Server,它需要接收http.Handler类型,正确用法是用它包裹业务handler。
内容的提问来源于stack exchange,提问作者user2453676
相关产品推荐
相关产品推荐

