This commit is contained in:
2025-08-24 13:01:09 +08:00
parent 61e51ad014
commit f028913eb8
36 changed files with 10420 additions and 70 deletions

View File

@@ -0,0 +1,358 @@
/*
server_test.go - Web服务器测试文件
测试HTTP服务器和API的各种功能
*/
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"webserver/models"
"webserver/server"
)
// TestHealthHandler 测试健康检查处理器
func TestHealthHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/health", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.HealthHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusOK {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusOK)
}
// 检查响应内容类型
expected := "application/json"
if ct := rr.Header().Get("Content-Type"); ct != expected {
t.Errorf("处理器返回错误内容类型: got %v want %v", ct, expected)
}
// 检查响应体
var response server.HealthResponse
if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if response.Status != "healthy" {
t.Errorf("期望状态为 'healthy', 实际为 '%s'", response.Status)
}
}
// TestGetUsersHandler 测试获取用户列表处理器
func TestGetUsersHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/api/users", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.GetUsersHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusOK {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusOK)
}
// 检查响应内容类型
expected := "application/json"
if ct := rr.Header().Get("Content-Type"); ct != expected {
t.Errorf("处理器返回错误内容类型: got %v want %v", ct, expected)
}
// 检查响应体
var response server.Response
if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if response.Status != "success" {
t.Errorf("期望状态为 'success', 实际为 '%s'", response.Status)
}
}
// TestCreateUserHandler 测试创建用户处理器
func TestCreateUserHandler(t *testing.T) {
user := models.User{
Name: "测试用户",
Email: "test@example.com",
Age: 25,
}
jsonData, err := json.Marshal(user)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", "/api/users", bytes.NewBuffer(jsonData))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.CreateUserHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusCreated {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusCreated)
}
// 检查响应体
var response server.Response
if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if response.Status != "success" {
t.Errorf("期望状态为 'success', 实际为 '%s'", response.Status)
}
}
// TestCreateUserHandlerInvalidData 测试创建用户处理器(无效数据)
func TestCreateUserHandlerInvalidData(t *testing.T) {
// 测试空用户名
user := models.User{
Name: "",
Email: "test@example.com",
Age: 25,
}
jsonData, err := json.Marshal(user)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", "/api/users", bytes.NewBuffer(jsonData))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.CreateUserHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusBadRequest {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusBadRequest)
}
// 检查响应体
var response server.Response
if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if response.Status != "error" {
t.Errorf("期望状态为 'error', 实际为 '%s'", response.Status)
}
}
// TestCreateUserHandlerInvalidJSON 测试创建用户处理器无效JSON
func TestCreateUserHandlerInvalidJSON(t *testing.T) {
invalidJSON := []byte(`{"name": "测试用户", "email": "test@example.com", "age":}`)
req, err := http.NewRequest("POST", "/api/users", bytes.NewBuffer(invalidJSON))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.CreateUserHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusBadRequest {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusBadRequest)
}
}
// TestStatsHandler 测试统计信息处理器
func TestStatsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/api/stats", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.StatsHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusOK {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusOK)
}
// 检查响应体
var response server.StatsResponse
if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if response.Status != "success" {
t.Errorf("期望状态为 'success', 实际为 '%s'", response.Status)
}
if response.NumCPU <= 0 {
t.Error("CPU数量应该大于0")
}
if response.NumGoroutine <= 0 {
t.Error("Goroutine数量应该大于0")
}
}
// TestAPIDocHandler 测试API文档处理器
func TestAPIDocHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/api", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.APIDocHandler)
handler.ServeHTTP(rr, req)
// 检查状态码
if status := rr.Code; status != http.StatusOK {
t.Errorf("处理器返回错误状态码: got %v want %v", status, http.StatusOK)
}
// 检查响应内容类型
expected := "application/json"
if ct := rr.Header().Get("Content-Type"); ct != expected {
t.Errorf("处理器返回错误内容类型: got %v want %v", ct, expected)
}
// 检查响应体包含API文档信息
var doc map[string]interface{}
if err := json.Unmarshal(rr.Body.Bytes(), &doc); err != nil {
t.Errorf("无法解析响应JSON: %v", err)
}
if _, exists := doc["title"]; !exists {
t.Error("API文档应该包含title字段")
}
if _, exists := doc["endpoints"]; !exists {
t.Error("API文档应该包含endpoints字段")
}
}
// TestServer 测试完整的服务器
func TestServer(t *testing.T) {
// 创建服务器
srv := server.NewServer(":0") // 使用随机端口
srv.SetupRoutes()
// 创建测试服务器
testServer := httptest.NewServer(srv.GetRouter())
defer testServer.Close()
// 测试健康检查
resp, err := http.Get(testServer.URL + "/health")
if err != nil {
t.Fatalf("健康检查请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("健康检查返回错误状态码: got %v want %v", resp.StatusCode, http.StatusOK)
}
// 测试获取用户列表
resp, err = http.Get(testServer.URL + "/api/users")
if err != nil {
t.Fatalf("获取用户列表请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("获取用户列表返回错误状态码: got %v want %v", resp.StatusCode, http.StatusOK)
}
}
// TestMiddleware 测试中间件
func TestMiddleware(t *testing.T) {
// 测试CORS中间件
req, err := http.NewRequest("OPTIONS", "/api/users", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
// 创建带中间件的处理器
handler := server.CORSMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
handler.ServeHTTP(rr, req)
// 检查CORS头
if origin := rr.Header().Get("Access-Control-Allow-Origin"); origin != "*" {
t.Errorf("期望CORS Origin为 '*', 实际为 '%s'", origin)
}
if methods := rr.Header().Get("Access-Control-Allow-Methods"); methods == "" {
t.Error("应该设置Access-Control-Allow-Methods头")
}
}
// BenchmarkHealthHandler 健康检查处理器基准测试
func BenchmarkHealthHandler(b *testing.B) {
req, _ := http.NewRequest("GET", "/health", nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.HealthHandler)
handler.ServeHTTP(rr, req)
}
}
// BenchmarkGetUsersHandler 获取用户列表处理器基准测试
func BenchmarkGetUsersHandler(b *testing.B) {
req, _ := http.NewRequest("GET", "/api/users", nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.GetUsersHandler)
handler.ServeHTTP(rr, req)
}
}
// ExampleHealthHandler 健康检查处理器示例
func ExampleHealthHandler() {
req, _ := http.NewRequest("GET", "/health", nil)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(server.HealthHandler)
handler.ServeHTTP(rr, req)
fmt.Printf("Status: %d", rr.Code)
// Output: Status: 200
}