init
This commit is contained in:
+363
@@ -0,0 +1,363 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SetupRouter 创建测试路由
|
||||
func SetupRouter() *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
return gin.New()
|
||||
}
|
||||
|
||||
// Request 测试请求辅助函数
|
||||
type Request struct {
|
||||
router *gin.Engine
|
||||
method string
|
||||
path string
|
||||
body any
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
// NewRequest 创建测试请求
|
||||
func NewRequest(router *gin.Engine, method, path string) *Request {
|
||||
return &Request{
|
||||
router: router,
|
||||
method: method,
|
||||
path: path,
|
||||
headers: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// GET 创建 GET 请求
|
||||
func GET(router *gin.Engine, path string) *Request {
|
||||
return NewRequest(router, http.MethodGet, path)
|
||||
}
|
||||
|
||||
// POST 创建 POST 请求
|
||||
func POST(router *gin.Engine, path string) *Request {
|
||||
return NewRequest(router, http.MethodPost, path)
|
||||
}
|
||||
|
||||
// PUT 创建 PUT 请求
|
||||
func PUT(router *gin.Engine, path string) *Request {
|
||||
return NewRequest(router, http.MethodPut, path)
|
||||
}
|
||||
|
||||
// DELETE 创建 DELETE 请求
|
||||
func DELETE(router *gin.Engine, path string) *Request {
|
||||
return NewRequest(router, http.MethodDelete, path)
|
||||
}
|
||||
|
||||
// PATCH 创建 PATCH 请求
|
||||
func PATCH(router *gin.Engine, path string) *Request {
|
||||
return NewRequest(router, http.MethodPatch, path)
|
||||
}
|
||||
|
||||
// WithBody 设置请求体
|
||||
func (r *Request) WithBody(body any) *Request {
|
||||
r.body = body
|
||||
return r
|
||||
}
|
||||
|
||||
// WithJSON 设置 JSON 请求体
|
||||
func (r *Request) WithJSON(body any) *Request {
|
||||
r.body = body
|
||||
r.headers["Content-Type"] = "application/json"
|
||||
return r
|
||||
}
|
||||
|
||||
// WithHeader 设置请求头
|
||||
func (r *Request) WithHeader(key, value string) *Request {
|
||||
r.headers[key] = value
|
||||
return r
|
||||
}
|
||||
|
||||
// WithToken 设置 Authorization 头
|
||||
func (r *Request) WithToken(token string) *Request {
|
||||
r.headers["Authorization"] = "Bearer " + token
|
||||
return r
|
||||
}
|
||||
|
||||
// Execute 执行请求
|
||||
func (r *Request) Execute() *httptest.ResponseRecorder {
|
||||
var bodyReader *bytes.Reader
|
||||
|
||||
if r.body != nil {
|
||||
bodyBytes, _ := json.Marshal(r.body)
|
||||
bodyReader = bytes.NewReader(bodyBytes)
|
||||
} else {
|
||||
bodyReader = bytes.NewReader([]byte{})
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(r.method, r.path, bodyReader)
|
||||
|
||||
for key, value := range r.headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
r.router.ServeHTTP(recorder, req)
|
||||
|
||||
return recorder
|
||||
}
|
||||
|
||||
// Response 响应解析辅助
|
||||
type Response struct {
|
||||
*httptest.ResponseRecorder
|
||||
}
|
||||
|
||||
// ParseJSON 解析 JSON 响应
|
||||
func (r *Response) ParseJSON(v any) error {
|
||||
return json.Unmarshal(r.Body.Bytes(), v)
|
||||
}
|
||||
|
||||
// AssertStatus 断言状态码
|
||||
func (r *Response) AssertStatus(t *testing.T, expected int) {
|
||||
t.Helper()
|
||||
if r.Code != expected {
|
||||
t.Errorf("状态码错误: 期望 %d, 实际 %d", expected, r.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// AssertOK 断言状态码为 200
|
||||
func (r *Response) AssertOK(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusOK)
|
||||
}
|
||||
|
||||
// AssertCreated 断言状态码为 201
|
||||
func (r *Response) AssertCreated(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusCreated)
|
||||
}
|
||||
|
||||
// AssertBadRequest 断言状态码为 400
|
||||
func (r *Response) AssertBadRequest(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// AssertUnauthorized 断言状态码为 401
|
||||
func (r *Response) AssertUnauthorized(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
// AssertForbidden 断言状态码为 403
|
||||
func (r *Response) AssertForbidden(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusForbidden)
|
||||
}
|
||||
|
||||
// AssertNotFound 断言状态码为 404
|
||||
func (r *Response) AssertNotFound(t *testing.T) {
|
||||
t.Helper()
|
||||
r.AssertStatus(t, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// AssertJSONContains 断言 JSON 包含指定字段
|
||||
func (r *Response) AssertJSONContains(t *testing.T, key string, expected any) {
|
||||
t.Helper()
|
||||
|
||||
var result map[string]any
|
||||
if err := r.ParseJSON(&result); err != nil {
|
||||
t.Errorf("解析 JSON 失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 支持嵌套键(如 "data.user.id")
|
||||
keys := splitKey(key)
|
||||
current := result
|
||||
|
||||
for i, k := range keys {
|
||||
if i == len(keys)-1 {
|
||||
if current[k] != expected {
|
||||
t.Errorf("JSON 字段 %s 错误: 期望 %v, 实际 %v", key, expected, current[k])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
next, ok := current[k].(map[string]any)
|
||||
if !ok {
|
||||
t.Errorf("JSON 字段 %s 不是对象", k)
|
||||
return
|
||||
}
|
||||
current = next
|
||||
}
|
||||
}
|
||||
|
||||
func splitKey(key string) []string {
|
||||
var keys []string
|
||||
start := 0
|
||||
for i := 0; i < len(key); i++ {
|
||||
if key[i] == '.' {
|
||||
keys = append(keys, key[start:i])
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
keys = append(keys, key[start:])
|
||||
return keys
|
||||
}
|
||||
|
||||
// Mock 模拟工具
|
||||
|
||||
// MockDB 模拟数据库(用于简单测试)
|
||||
type MockDB struct {
|
||||
data map[any]any
|
||||
}
|
||||
|
||||
// NewMockDB 创建模拟数据库
|
||||
func NewMockDB() *MockDB {
|
||||
return &MockDB{
|
||||
data: make(map[any]any),
|
||||
}
|
||||
}
|
||||
|
||||
// Set 设置数据
|
||||
func (m *MockDB) Set(key, value any) {
|
||||
m.data[key] = value
|
||||
}
|
||||
|
||||
// Get 获取数据
|
||||
func (m *MockDB) Get(key any) (any, bool) {
|
||||
v, ok := m.data[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// Delete 删除数据
|
||||
func (m *MockDB) Delete(key any) {
|
||||
delete(m.data, key)
|
||||
}
|
||||
|
||||
// Clear 清空数据
|
||||
func (m *MockDB) Clear() {
|
||||
m.data = make(map[any]any)
|
||||
}
|
||||
|
||||
// MockCache 模拟缓存
|
||||
type MockCache struct {
|
||||
data map[string][]byte
|
||||
}
|
||||
|
||||
// NewMockCache 创建模拟缓存
|
||||
func NewMockCache() *MockCache {
|
||||
return &MockCache{
|
||||
data: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
// Set 设置缓存
|
||||
func (m *MockCache) Set(key string, value []byte) {
|
||||
m.data[key] = value
|
||||
}
|
||||
|
||||
// Get 获取缓存
|
||||
func (m *MockCache) Get(key string) ([]byte, bool) {
|
||||
v, ok := m.data[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// Delete 删除缓存
|
||||
func (m *MockCache) Delete(key string) {
|
||||
delete(m.data, key)
|
||||
}
|
||||
|
||||
// Exists 检查缓存是否存在
|
||||
func (m *MockCache) Exists(key string) bool {
|
||||
_, ok := m.data[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Clear 清空缓存
|
||||
func (m *MockCache) Clear() {
|
||||
m.data = make(map[string][]byte)
|
||||
}
|
||||
|
||||
// MockStorage 模拟存储
|
||||
type MockStorage struct {
|
||||
files map[string][]byte
|
||||
urls map[string]string
|
||||
}
|
||||
|
||||
// NewMockStorage 创建模拟存储
|
||||
func NewMockStorage() *MockStorage {
|
||||
return &MockStorage{
|
||||
files: make(map[string][]byte),
|
||||
urls: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// Upload 模拟上传
|
||||
func (m *MockStorage) Upload(data []byte, filename string) (string, error) {
|
||||
path := "/mock/" + filename
|
||||
m.files[path] = data
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// GetURL 获取 URL
|
||||
func (m *MockStorage) GetURL(path string) string {
|
||||
return "http://mock.test" + path
|
||||
}
|
||||
|
||||
// AssertEqual 通用相等断言
|
||||
func AssertEqual(t *testing.T, expected, actual any) {
|
||||
t.Helper()
|
||||
if expected != actual {
|
||||
t.Errorf("不相等: 期望 %v, 实际 %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
// AssertNotNil 断言不为空
|
||||
func AssertNotNil(t *testing.T, value any) {
|
||||
t.Helper()
|
||||
if value == nil {
|
||||
t.Error("期望非空,实际为空")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertNil 断言为空
|
||||
func AssertNil(t *testing.T, value any) {
|
||||
t.Helper()
|
||||
if value != nil {
|
||||
t.Errorf("期望为空,实际为: %v", value)
|
||||
}
|
||||
}
|
||||
|
||||
// AssertTrue 断言为真
|
||||
func AssertTrue(t *testing.T, value bool) {
|
||||
t.Helper()
|
||||
if !value {
|
||||
t.Error("期望为真,实际为假")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertFalse 断言为假
|
||||
func AssertFalse(t *testing.T, value bool) {
|
||||
t.Helper()
|
||||
if value {
|
||||
t.Error("期望为假,实际为真")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertError 断言有错误
|
||||
func AssertError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err == nil {
|
||||
t.Error("期望有错误,实际无错误")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertNoError 断言无错误
|
||||
func AssertNoError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Errorf("期望无错误,实际错误: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user