feat: 添加服务和数据库初始化
This commit is contained in:
356
app_test.go
Normal file
356
app_test.go
Normal file
@@ -0,0 +1,356 @@
|
||||
package go_web_gin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// AppTestSuite is the test suite for App
|
||||
type AppTestSuite struct {
|
||||
suite.Suite
|
||||
app *App
|
||||
}
|
||||
|
||||
// SetupSuite runs once before all tests
|
||||
func (s *AppTestSuite) SetupSuite() {
|
||||
gin.SetMode(gin.TestMode)
|
||||
s.app = New()
|
||||
}
|
||||
|
||||
// TearDownSuite runs once after all tests
|
||||
func (s *AppTestSuite) TearDownSuite() {
|
||||
// Cleanup if needed
|
||||
}
|
||||
|
||||
// SetupTest runs before each test
|
||||
func (s *AppTestSuite) SetupTest() {
|
||||
// Reset state if needed
|
||||
}
|
||||
|
||||
// TearDownTest runs after each test
|
||||
func (s *AppTestSuite) TearDownTest() {
|
||||
// Cleanup after each test if needed
|
||||
}
|
||||
|
||||
// TestNew tests the New function
|
||||
func (s *AppTestSuite) TestNew() {
|
||||
app := New()
|
||||
s.NotNil(app, "New should return a non-nil App")
|
||||
s.NotNil(app.engine, "engine should be initialized")
|
||||
s.NotNil(app.logger, "logger should be initialized")
|
||||
}
|
||||
|
||||
// TestNewSingleton tests that svr.GetEngine returns the same instance
|
||||
func (s *AppTestSuite) TestNewSingleton() {
|
||||
app1 := New()
|
||||
app2 := New()
|
||||
s.Equal(app1.engine, app2.engine, "engine should be singleton")
|
||||
}
|
||||
|
||||
// TestUseMiddleware tests the UseMiddleware method
|
||||
func (s *AppTestSuite) TestUseMiddleware() {
|
||||
middlewareCalled := false
|
||||
middleware := func(c *gin.Context) {
|
||||
middlewareCalled = true
|
||||
c.Next()
|
||||
}
|
||||
|
||||
s.app.UseMiddleware(middleware)
|
||||
|
||||
// Create a test route to verify middleware
|
||||
s.app.engine.GET("/test-middleware", func(c *gin.Context) {
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/test-middleware", nil)
|
||||
w := httptest.NewRecorder()
|
||||
s.app.engine.ServeHTTP(w, req)
|
||||
|
||||
s.True(middlewareCalled, "middleware should be called")
|
||||
}
|
||||
|
||||
// TestRegisterRoutes tests the RegisterRoutes method
|
||||
func (s *AppTestSuite) TestRegisterRoutes() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/test-route", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "ok"})
|
||||
})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/test-route", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
s.Contains(w.Body.String(), "ok")
|
||||
}
|
||||
|
||||
// TestRegisterRoutesMultiple tests registering multiple routes
|
||||
func (s *AppTestSuite) TestRegisterRoutesMultiple() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/route1", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"route": 1})
|
||||
})
|
||||
e.POST("/route2", func(c *gin.Context) {
|
||||
c.JSON(http.StatusCreated, gin.H{"route": 2})
|
||||
})
|
||||
e.PUT("/route3", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"route": 3})
|
||||
})
|
||||
})
|
||||
|
||||
// Test GET
|
||||
req1 := httptest.NewRequest("GET", "/route1", nil)
|
||||
w1 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w1, req1)
|
||||
s.Equal(http.StatusOK, w1.Code)
|
||||
|
||||
// Test POST
|
||||
req2 := httptest.NewRequest("POST", "/route2", nil)
|
||||
w2 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w2, req2)
|
||||
s.Equal(http.StatusCreated, w2.Code)
|
||||
|
||||
// Test PUT
|
||||
req3 := httptest.NewRequest("PUT", "/route3", nil)
|
||||
w3 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w3, req3)
|
||||
s.Equal(http.StatusOK, w3.Code)
|
||||
}
|
||||
|
||||
// TestDB tests the DB method returns nil when not initialized
|
||||
func (s *AppTestSuite) TestDB() {
|
||||
app := New()
|
||||
s.Nil(app.DB(), "DB should be nil when not initialized")
|
||||
}
|
||||
|
||||
// TestRedis tests the Redis method returns nil when not initialized
|
||||
func (s *AppTestSuite) TestRedis() {
|
||||
app := New()
|
||||
s.Nil(app.Redis(), "Redis should be nil when not initialized")
|
||||
}
|
||||
|
||||
// TestLogger tests the Logger method
|
||||
func (s *AppTestSuite) TestLogger() {
|
||||
app := New()
|
||||
logger := app.Logger()
|
||||
s.NotNil(logger, "Logger should not be nil")
|
||||
}
|
||||
|
||||
// TestLoggerNotNil tests that logger is always initialized
|
||||
func (s *AppTestSuite) TestLoggerNotNil() {
|
||||
s.NotNil(s.app.Logger(), "Logger should always be initialized in New()")
|
||||
}
|
||||
|
||||
// TestLoggerMethods tests that logger methods work
|
||||
func (s *AppTestSuite) TestLoggerMethods() {
|
||||
s.NotPanics(func() {
|
||||
s.app.Logger().Info(nil, "Test info message")
|
||||
s.app.Logger().Debug(nil, "Test debug message")
|
||||
s.app.Logger().Warn(nil, "Test warn message")
|
||||
}, "Logger methods should not panic")
|
||||
}
|
||||
|
||||
// TestLoggerWithContext tests logger with context
|
||||
func (s *AppTestSuite) TestLoggerWithContext() {
|
||||
ctx := context.Background()
|
||||
s.NotPanics(func() {
|
||||
s.app.Logger().Info(ctx, "Test with context")
|
||||
}, "Logger should work with context")
|
||||
}
|
||||
|
||||
// TestRunInvalidAddress tests Run with invalid address
|
||||
func (s *AppTestSuite) TestRunInvalidAddress() {
|
||||
app := New()
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/ping", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"pong": true})
|
||||
})
|
||||
})
|
||||
|
||||
// Use a channel to handle the async nature of Run
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- app.Run("invalid:address:format")
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
s.Error(err, "Run should return error for invalid address")
|
||||
case <-time.After(2 * time.Second):
|
||||
// Server might start, which is fine for this test
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTTPMethod tests various HTTP methods
|
||||
func (s *AppTestSuite) TestHTTPMethod() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.DELETE("/delete", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"deleted": true})
|
||||
})
|
||||
e.PATCH("/patch", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"patched": true})
|
||||
})
|
||||
e.OPTIONS("/options", func(c *gin.Context) {
|
||||
c.Status(http.StatusNoContent)
|
||||
})
|
||||
e.HEAD("/head", func(c *gin.Context) {
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
// Test DELETE
|
||||
req := httptest.NewRequest("DELETE", "/delete", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
|
||||
// Test PATCH
|
||||
req2 := httptest.NewRequest("PATCH", "/patch", nil)
|
||||
w2 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w2, req2)
|
||||
s.Equal(http.StatusOK, w2.Code)
|
||||
|
||||
// Test OPTIONS
|
||||
req3 := httptest.NewRequest("OPTIONS", "/options", nil)
|
||||
w3 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w3, req3)
|
||||
s.Equal(http.StatusNoContent, w3.Code)
|
||||
|
||||
// Test HEAD
|
||||
req4 := httptest.NewRequest("HEAD", "/head", nil)
|
||||
w4 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w4, req4)
|
||||
s.Equal(http.StatusOK, w4.Code)
|
||||
}
|
||||
|
||||
// TestRouteGroup tests route groups
|
||||
func (s *AppTestSuite) TestRouteGroup() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
api := e.Group("/api")
|
||||
{
|
||||
api.GET("/users", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"users": []string{}})
|
||||
})
|
||||
api.GET("/posts", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"posts": []string{}})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
req1 := httptest.NewRequest("GET", "/api/users", nil)
|
||||
w1 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w1, req1)
|
||||
s.Equal(http.StatusOK, w1.Code)
|
||||
|
||||
req2 := httptest.NewRequest("GET", "/api/posts", nil)
|
||||
w2 := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w2, req2)
|
||||
s.Equal(http.StatusOK, w2.Code)
|
||||
}
|
||||
|
||||
// TestMiddlewareChain tests middleware chain
|
||||
func (s *AppTestSuite) TestMiddlewareChain() {
|
||||
app := New()
|
||||
order := []string{}
|
||||
|
||||
app.UseMiddleware(func(c *gin.Context) {
|
||||
order = append(order, "middleware1-before")
|
||||
c.Next()
|
||||
order = append(order, "middleware1-after")
|
||||
})
|
||||
|
||||
app.UseMiddleware(func(c *gin.Context) {
|
||||
order = append(order, "middleware2-before")
|
||||
c.Next()
|
||||
order = append(order, "middleware2-after")
|
||||
})
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/chain", func(c *gin.Context) {
|
||||
order = append(order, "handler")
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/chain", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
|
||||
expected := []string{
|
||||
"middleware1-before",
|
||||
"middleware2-before",
|
||||
"handler",
|
||||
"middleware2-after",
|
||||
"middleware1-after",
|
||||
}
|
||||
s.Equal(expected, order, "middleware should execute in correct order")
|
||||
}
|
||||
|
||||
// TestQueryParam tests query parameters
|
||||
func (s *AppTestSuite) TestQueryParam() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/search", func(c *gin.Context) {
|
||||
q := c.Query("q")
|
||||
c.JSON(http.StatusOK, gin.H{"query": q})
|
||||
})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/search?q=test", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
s.Contains(w.Body.String(), "test")
|
||||
}
|
||||
|
||||
// TestPathParam tests path parameters
|
||||
func (s *AppTestSuite) TestPathParam() {
|
||||
app := New()
|
||||
|
||||
app.RegisterRoutes(func(e *gin.Engine) {
|
||||
e.GET("/users/:id", func(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
c.JSON(http.StatusOK, gin.H{"user_id": id})
|
||||
})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/users/123", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
s.Contains(w.Body.String(), "123")
|
||||
}
|
||||
|
||||
// TestNotFound tests 404 handling
|
||||
func (s *AppTestSuite) TestNotFound() {
|
||||
app := New()
|
||||
|
||||
req := httptest.NewRequest("GET", "/nonexistent", nil)
|
||||
w := httptest.NewRecorder()
|
||||
app.engine.ServeHTTP(w, req)
|
||||
|
||||
s.Equal(http.StatusNotFound, w.Code)
|
||||
}
|
||||
|
||||
// TestAppRunSuite runs the test suite
|
||||
func TestAppRunSuite(t *testing.T) {
|
||||
suite.Run(t, new(AppTestSuite))
|
||||
}
|
||||
Reference in New Issue
Block a user