This commit is contained in:
sjk
2025-11-17 13:39:05 +08:00
commit d4cfe2b9de
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
package handler
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
// 测试用的请求结构
type TestRegisterRequest struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
type TestLoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
func TestAuthHandler_Register(t *testing.T) {
// 设置Gin为测试模式
gin.SetMode(gin.TestMode)
tests := []struct {
name string
request TestRegisterRequest
expectedStatus int
}{
{
name: "有效注册请求",
request: TestRegisterRequest{
Username: "testuser",
Email: "test@example.com",
Password: "password123",
},
expectedStatus: http.StatusOK, // 注意实际可能返回201或其他状态码
},
{
name: "无效请求 - 缺少用户名",
request: TestRegisterRequest{
Username: "",
Email: "test@example.com",
Password: "password123",
},
expectedStatus: http.StatusBadRequest,
},
{
name: "无效请求 - 缺少邮箱",
request: TestRegisterRequest{
Username: "testuser",
Email: "",
Password: "password123",
},
expectedStatus: http.StatusBadRequest,
},
{
name: "无效请求 - 缺少密码",
request: TestRegisterRequest{
Username: "testuser",
Email: "test@example.com",
Password: "",
},
expectedStatus: http.StatusBadRequest,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 创建请求体
requestBody, err := json.Marshal(tt.request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", "/api/auth/register", bytes.NewBuffer(requestBody))
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
// 创建响应记录器
w := httptest.NewRecorder()
// 创建Gin上下文
c, _ := gin.CreateTestContext(w)
c.Request = req
// 注意这里需要实际的AuthHandler实例
// 由于没有数据库连接,这个测试会失败
// 这里只是展示测试结构
// 验证请求格式(基本验证)
if tt.request.Username == "" || tt.request.Email == "" || tt.request.Password == "" {
if w.Code != tt.expectedStatus && tt.expectedStatus == http.StatusBadRequest {
// 这是预期的错误情况
t.Logf("Expected bad request for invalid input: %+v", tt.request)
}
} else {
t.Logf("Valid request format: %+v", tt.request)
}
})
}
}
func TestAuthHandler_Login(t *testing.T) {
gin.SetMode(gin.TestMode)
tests := []struct {
name string
request TestLoginRequest
expectedStatus int
}{
{
name: "有效登录请求",
request: TestLoginRequest{
Username: "testuser",
Password: "password123",
},
expectedStatus: http.StatusOK,
},
{
name: "无效请求 - 缺少用户名",
request: TestLoginRequest{
Username: "",
Password: "password123",
},
expectedStatus: http.StatusBadRequest,
},
{
name: "无效请求 - 缺少密码",
request: TestLoginRequest{
Username: "testuser",
Password: "",
},
expectedStatus: http.StatusBadRequest,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 创建请求体
requestBody, err := json.Marshal(tt.request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", "/api/auth/login", bytes.NewBuffer(requestBody))
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
// 创建响应记录器
w := httptest.NewRecorder()
// 创建Gin上下文
c, _ := gin.CreateTestContext(w)
c.Request = req
// 验证请求格式(基本验证)
if tt.request.Username == "" || tt.request.Password == "" {
if tt.expectedStatus == http.StatusBadRequest {
t.Logf("Expected bad request for invalid input: %+v", tt.request)
}
} else {
t.Logf("Valid request format: %+v", tt.request)
}
})
}
}
// 测试JSON解析
func TestJSONParsing(t *testing.T) {
tests := []struct {
name string
jsonStr string
valid bool
}{
{
name: "有效JSON",
jsonStr: `{"username":"test","email":"test@example.com","password":"123456"}`,
valid: true,
},
{
name: "无效JSON",
jsonStr: `{"username":"test","email":"test@example.com","password":}`,
valid: false,
},
{
name: "空JSON",
jsonStr: `{}`,
valid: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var req TestRegisterRequest
err := json.Unmarshal([]byte(tt.jsonStr), &req)
if tt.valid && err != nil {
t.Errorf("Expected valid JSON, got error: %v", err)
}
if !tt.valid && err == nil {
t.Errorf("Expected invalid JSON, but parsing succeeded")
}
})
}
}
// 测试HTTP状态码常量
func TestHTTPStatusCodes(t *testing.T) {
expectedCodes := map[string]int{
"OK": http.StatusOK,
"Created": http.StatusCreated,
"BadRequest": http.StatusBadRequest,
"Unauthorized": http.StatusUnauthorized,
"InternalServerError": http.StatusInternalServerError,
}
for name, expectedCode := range expectedCodes {
t.Run(name, func(t *testing.T) {
if expectedCode <= 0 {
t.Errorf("Invalid status code for %s: %d", name, expectedCode)
}
t.Logf("%s status code: %d", name, expectedCode)
})
}
}

View File

@@ -0,0 +1,63 @@
package handler
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/api/handlers"
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/common"
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/services"
)
type MockVocabularyService struct {
mock.Mock
}
// 显式实现 VocabularyServiceInterface 接口
var _ interfaces.VocabularyServiceInterface = (*MockVocabularyService)(nil)
func (m *MockVocabularyService) GetDailyStats(userID string) (map[string]interface{}, error) {
args := m.Called(userID)
return args.Get(0).(map[string]interface{}), args.Error(1)
}
func TestGetDailyVocabularyStats(t *testing.T) {
// 初始化 Gin 引擎
gin.SetMode(gin.TestMode)
r := gin.Default()
// 创建 Mock 服务
mockService := new(MockVocabularyService)
mockService.On("GetDailyStats", "test_user").Return(map[string]interface{}{
"wordsLearned": 10,
"studyTimeMinutes": 30,
}, nil)
mockService.On("GetDailyStats", "").Return(nil, common.NewBusinessError(400, "用户ID不能为空"))
// 创建处理器
h := handlers.NewVocabularyHandler(mockService, nil)
r.GET("/api/vocabulary/daily", h.GetDailyVocabularyStats)
// 测试成功情况
req, _ := http.NewRequest(http.MethodGet, "/api/vocabulary/daily?user_id=test_user", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "wordsLearned")
assert.Contains(t, w.Body.String(), "studyTimeMinutes")
// 测试缺少用户ID
req, _ = http.NewRequest(http.MethodGet, "/api/vocabulary/daily", nil)
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "用户ID不能为空")
}