package handler_test import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/user-management-system/internal/api/handler" "github.com/user-management-system/internal/cache" "github.com/user-management-system/internal/service" ) // ============================================================================= // Captcha Handler Tests - TDD approach // ============================================================================= func TestCaptchaHandler_GenerateCaptcha(t *testing.T) { gin.SetMode(gin.TestMode) l1Cache := cache.NewL1Cache() l2Cache := cache.NewRedisCache(false) cacheManager := cache.NewCacheManager(l1Cache, l2Cache) captchaSvc := service.NewCaptchaService(cacheManager) h := handler.NewCaptchaHandler(captchaSvc) t.Run("生成验证码成功", func(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("GET", "/api/v1/captcha/generate", nil) h.GenerateCaptcha(c) if w.Code != http.StatusOK { t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code) } var resp map[string]interface{} if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { t.Fatalf("解析响应失败: %v", err) } if resp["code"].(float64) != 0 { t.Errorf("期望 code=0, 得到 %v", resp["code"]) } data := resp["data"].(map[string]interface{}) if data["captcha_id"] == "" { t.Error("captcha_id 不应为空") } if data["image"] == "" { t.Error("image 不应为空") } }) } func TestCaptchaHandler_VerifyCaptcha(t *testing.T) { gin.SetMode(gin.TestMode) l1Cache := cache.NewL1Cache() l2Cache := cache.NewRedisCache(false) cacheManager := cache.NewCacheManager(l1Cache, l2Cache) captchaSvc := service.NewCaptchaService(cacheManager) h := handler.NewCaptchaHandler(captchaSvc) t.Run("验证成功", func(t *testing.T) { // 先生成验证码 result, _ := captchaSvc.Generate(nil) // 从缓存获取答案 cachedVal, ok := cacheManager.Get(nil, "captcha:"+result.CaptchaID) if !ok { t.Fatal("验证码未存储到缓存") } answer := cachedVal.(string) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) body := `{"captcha_id":"` + result.CaptchaID + `","answer":"` + answer + `"}` c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil) c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body))) c.Request.Header.Set("Content-Type", "application/json") h.VerifyCaptcha(c) if w.Code != http.StatusOK { t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code) } }) t.Run("验证失败-错误答案", func(t *testing.T) { result, _ := captchaSvc.Generate(nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) body := `{"captcha_id":"` + result.CaptchaID + `","answer":"wrong"}` c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil) c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body))) c.Request.Header.Set("Content-Type", "application/json") h.VerifyCaptcha(c) if w.Code != http.StatusBadRequest { t.Errorf("期望状态码 %d, 得到 %d", http.StatusBadRequest, w.Code) } }) t.Run("验证失败-缺少参数", func(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) body := `{"captcha_id":""}` c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil) c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body))) c.Request.Header.Set("Content-Type", "application/json") h.VerifyCaptcha(c) if w.Code != http.StatusBadRequest { t.Errorf("期望状态码 %d, 得到 %d", http.StatusBadRequest, w.Code) } }) } func TestCaptchaHandler_GetCaptchaImage(t *testing.T) { gin.SetMode(gin.TestMode) l1Cache := cache.NewL1Cache() l2Cache := cache.NewRedisCache(false) cacheManager := cache.NewCacheManager(l1Cache, l2Cache) captchaSvc := service.NewCaptchaService(cacheManager) h := handler.NewCaptchaHandler(captchaSvc) t.Run("获取验证码图片", func(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("GET", "/api/v1/captcha/image?captcha_id=test", nil) h.GetCaptchaImage(c) if w.Code != http.StatusOK { t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code) } }) }