gin单元测试启动服务后测试controller接口
1、使用的包是 net/http/httptest
2、单元测试需要启动 gin 服务,然后 httptest.NewRequest 发送请求
示例代码:
mkdir gin
cd gin
go mod init example.com
go get github.com/gin-gonic/gin go get github.com/stretchr/testify
创建 web 控制器
cd gin
mkdir controller
touch user.go
touch user_test.go
其中 user.go 的内容
package controller import ( "fmt" "net/http" "github.com/gin-gonic/gin" ) // Param 请求参数 type Param struct { Name string `json:"name"` } // helloHandler /hello请求处理函数 func helloHandler(c *gin.Context) { var p Param if err := c.ShouldBindJSON(&p); err != nil { c.JSON(http.StatusOK, gin.H{ "msg": "we need a name", }) return } c.JSON(http.StatusOK, gin.H{ "msg": fmt.Sprintf("hello %s", p.Name), }) } // SetupRouter 路由 func SetupRouter() *gin.Engine { router := gin.Default() router.POST("/hello", helloHandler) return router }
单元测试代码 user_test.go
package controller import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" ) type p struct { name string param string expect string } // go test -timeout 30s -run ^Test_helloHandler$ example.com/controller func Test_helloHandler(t *testing.T) { // 定义两个测试用例 tests := []p{ {"base case", `{"name": "jack"}`, "hello jack"}, {"bad case", "", "we need a name"}, } r := SetupRouter() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // mock一个HTTP请求 req := httptest.NewRequest("POST", "/hello", strings.NewReader(tt.param)) // mock一个响应记录器 w := httptest.NewRecorder() // 让server端处理mock请求并记录返回的响应内容 r.ServeHTTP(w, req) // 校验状态码是否符合预期 assert.Equal(t, http.StatusOK, w.Code) // 解析并检验响应内容是否复合预期 var resp map[string]string err := json.Unmarshal(w.Body.Bytes(), &resp) assert.Nil(t, err) assert.Equal(t, tt.expect, resp["msg"]) }) } }
在controller所在的目录执行用例 (用 goland 和 vscode 都可以 , 用goland 可以很方便地看单元测试代码覆盖率)
cd controller
go test -timeout 30s -run ^Test_helloHandler$ example.com/controller
需要启动 gin 服务器相对比较麻烦
I can see a bigger world.