الاختبار
كيف تكتب حالات اختبار لـ Gin؟
حزمة net/http/httptest هي الطريقة المفضلة لاختبار HTTP.
إخفاء مخرجات التصحيح
استدعِ gin.SetMode(gin.TestMode) قبل إنشاء الموجّه في اختباراتك. هذا يخفي سجلات تسجيل المسارات على مستوى التصحيح التي يطبعها Gin افتراضياً، مما يبقي مخرجات اختباراتك نظيفة. يمكنك وضع هذا في TestMain ليُطبق على جميع الاختبارات في الحزمة:
func TestMain(m *testing.M) { gin.SetMode(gin.TestMode) os.Exit(m.Run())}تطبيق مثال
package main
import "github.com/gin-gonic/gin"
type User struct { Username string `json:"username"` Gender string `json:"gender"`}
func setupRouter() *gin.Engine { router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) return router}
func postUser(router *gin.Engine) *gin.Engine { router.POST("/user/add", func(c *gin.Context) { var user User c.BindJSON(&user) c.JSON(200, user) }) return router}
func main() { router := setupRouter() router = postUser(router) router.Run(":8080")}اختبارات أساسية
package main
import ( "net/http" "net/http/httptest" "encoding/json" "testing" "strings"
"github.com/stretchr/testify/assert")
func TestPingRoute(t *testing.T) { router := setupRouter()
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/ping", nil) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) assert.Equal(t, "pong", w.Body.String())}
// Test for POST /user/addfunc TestPostUser(t *testing.T) { router := setupRouter() router = postUser(router)
w := httptest.NewRecorder()
// Create an example user for testing exampleUser := User{ Username: "test_name", Gender: "male", } userJson, _ := json.Marshal(exampleUser) req, _ := http.NewRequest("POST", "/user/add", strings.NewReader(string(userJson))) router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code) // Compare the response body with the json data of exampleUser assert.Equal(t, string(userJson), w.Body.String())}اختبارات مبنية على الجداول
تتيح لك الاختبارات المبنية على الجداول تغطية العديد من مجموعات المدخلات/المخرجات دون تكرار منطق الاختبار. هذا النمط اصطلاحي في Go ويعمل بشكل جيد مع Gin:
func TestPingRouteTableDriven(t *testing.T) { router := setupRouter()
tests := []struct { name string method string path string wantCode int wantBody string }{ {"ping endpoint", "GET", "/ping", 200, "pong"}, {"not found", "GET", "/nonexistent", 404, ""}, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest(tt.method, tt.path, nil) router.ServeHTTP(w, req)
assert.Equal(t, tt.wantCode, w.Code) if tt.wantBody != "" { assert.Equal(t, tt.wantBody, w.Body.String()) } }) }}اختبار الوسيطات
لاختبار وسيط بشكل منفصل، أنشئ موجّهاً بسيطاً مع الوسيط المُطبق ومعالج بسيط يسجّل النتيجة:
func TestAuthMiddleware(t *testing.T) { gin.SetMode(gin.TestMode)
// Create a router with the middleware under test router := gin.New() router.Use(AuthRequired()) // your middleware
router.GET("/protected", func(c *gin.Context) { c.String(200, "ok") })
// Test without credentials -- expect 401 w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/protected", nil) router.ServeHTTP(w, req) assert.Equal(t, 401, w.Code)
// Test with valid credentials -- expect 200 w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer valid-token") router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code)}