在用Gin框架編寫了一個web server以後,咱們若是須要測試handlers接口函數的話,主要能夠採用兩種方式來進行。git
第一種是部署web server,而後經過瀏覽器或其餘http請求模擬工具來手動模擬真實的http請求,發送http請求以後,解析返回的響應,查看響應是否符合預期;這種作法比較麻煩,並且測試結果不太可靠。github
第二種是使用httptest結合testing來實現針對handlers接口函數的單元測試。web
github項目地址:https://github.com/Valiben/gin_unit_testjson
下面以一個簡單的登陸handler爲例子,來講明基於Gin框架的單元測試的方法。瀏覽器
首先定義接口處理函數:框架
type User struct { Username string `form:"username" json:"username" binding:"required"` Password string `form:"password" json:"password" binding:"required"` Age int `form:"age" json:"age" binding:"required"` } func LoginHandler(c *gin.Context) { req := &User{} if err := c.Bind(req); err != nil { log.Printf("err:%v", err) c.JSON(http.StatusOK, gin.H{ "errno": "1", "errmsg": "parameters not match", }) return } // judge the password and username if req.UserName != "Valiben" || req.Password != "123456" { c.JSON(http.StatusOK, gin.H{ "errno": "2", "errmsg": "password or username is wrong", }) return } c.JSON(http.StatusOK, gin.H{ "errno": "0", "errmsg": "login success", }) }
接下來,在單元測試文件中導入上述包:函數
import utils "github.com/Valiben/gin_unit_test"
搭建路由,將engine設置到utils中:工具
router := gin.Default() router.POST("/login", LoginHandler) utils.SetRouter(router)
設置好engine以後你就能夠像下面同樣編寫一個單元測試用例來測試登陸接口了:單元測試
type OrdinaryResponse struct { Errno string `json:"errno"` Errmsg string `json:"errmsg"` } func TestLoginHandler(t *testing.T) { resp := OrdinaryResponse{} err := utils.TestHandlerUnMarshalResp(utils.POST, "/login", utils.Form, user, &resp) if err != nil { t.Errorf("TestLoginHandler: %v\n", err) return } if resp.Errno != "0" { t.Errorf("TestLoginHandler: response is not expected\n") return } }
而後就能夠運行這個單元測試來檢驗接口函數啦,是否是很簡單呢。測試
若是是上傳文件之類的接口的單元測試,怎麼來寫呢,假設上傳文件的接口函數以下:
type FileRequest struct { FileName string `json:"file_name" form:"file_name" binding:"required"` UploadName string `json:"upload_name" form:"upload_name" binding:"required"` } func SaveFileHandler(c *gin.Context) { req := &FileRequest{} if err := c.Bind(req); err != nil { log.Printf("err:%v", err) c.JSON(http.StatusOK, gin.H{ "errno": "1", "errmsg": "parameters not match", }) return } // get the file of the request file, _, _ := c.Request.FormFile("file") if file == nil { c.JSON(http.StatusOK, gin.H{ "errno": "2", "errmsg": "file is nil", }) return } fmt.Printf("SaveFile: req:%+v\n", req) out, err := os.Create("test2.txt") if err != nil { c.JSON(http.StatusOK, gin.H{ "errno": "2", "errmsg": err.Error(), }) return } // copy the content of the file to the out _, err = io.Copy(out, file) defer file.Close() defer out.Close() if err != nil { c.JSON(http.StatusOK, gin.H{ "errno": "2", "errmsg": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "errno": "0", "errmsg": "save file success", }) }
再把接口函數設置到路由中,那麼單元測試就能夠這樣來寫啦:
func TestSaveFileHandler(t *testing.T) { param := make(map[string]interface{}) param["file_name"] = "test1.txt" param["upload_name"] = "Valiben" resp := OrdinaryResponse{} err := utils.TestFileHandlerUnMarshalResp(utils.POST, "/upload", (param["file_name"]).(string), "file", param, &resp) if err != nil { t.Errorf("TestSaveFileHandler: %v\n", err) return } if resp.Errno != "0" { t.Errorf("TestSaveFileHandler: response is not expected\n") return } }
file_name是文件路徑名,能夠是相對路徑也能夠是絕對路徑,該測試函數模擬調用/upload請求,上傳當前路徑下的test1.txt。
除此以外,小demo還支持自定義請求頭(諸如jwt-token等),更多用法能夠看小demo中的test/handlers_test哦