Gin框架Handler单元测试

Gin是Go语言的一个高性能web框架,而单元测试是开发的一个非常重要的环节,可以在应用发布之前发现问题。

今天我们就来看看Gin的处理程序单元测试如何写。首先我们用gin创建一个”hello word“ HTTP服务器。

package main
import (
   "net/http"
   "github.com/gin-gonic/gin"
)
func IndexHandler(c *gin.Context) {
   c.JSON(http.StatusOK, gin.H{
       "message": "hello world",
   })
}
func SetupServer() *gin.Engine {
   r := gin.Default()
   r.GET("/", IndexHandler)
   return r
}
func main() {
   SetupServer().Run()
}

运行上面的应用程序,然后对http://localhost:8080发起一个GET请求,将收到“hello world”字符串。

$ curl localhost:8080
{"message":"hello world"}”

上面的代码使用SetupServer()函数返回*gin.Engine实例,便于后续使用httpserver模拟服务端,如下所示:

package main

func TestIndexHandler(t *testing.T) {
   mockUserResp := `{"message":"hello world"}`
   ts := httptest.NewServer(SetupServer())
   defer ts.Close()

   resp, err := http.Get(fmt.Sprintf("%s/", ts.URL))
   if err != nil {
       t.Fatalf("Expected no error, got %v", err)
   }
   defer resp.Body.Close()

   if resp.StatusCode != http.StatusOK {”
        “t.Fatalf("Expected status code 200, got %v", resp.StatusCode)
   }
   responseData, _ := ioutil.ReadAll(resp.Body)
   if string(responseData) != mockUserResp {
       t.Fatalf("Expected hello world message, got %v", responseData)
   }
}

运行测试用例结果如下:

/usr/local/go/bin/go tool test2json -t /private/var/folders/x6/8wtj7zfd7r59wpk5fmjln2p40000gn/T/___TestIndexHandler_in_awesomeProject -test.v -test.paniconexit0 -test.run ^\QTestIndexHandler\E$
=== RUN   TestIndexHandler
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> awesomeProject.IndexHandler (3 handlers)
[GIN] 2022/02/03 - 23:44:02 | 200 |      72.875µs |       127.0.0.1 | GET      "/"
--- PASS: TestIndexHandler (0.00s)
PASS

虽然您可以使用testing包编写完整的测试,但您也可以安装第三方包testify来使用高级断言。要做到这一点,请遵循以下步骤:
1、下载testify第三方包:

Go get github.com/stretchr/testify

2、更新测试用例TestIndexHandler,使用testify包的assert属性:

func TestIndexHandler(t *testing.T) {
   mockUserResp := `{"message":"hello world"}`
   ts := httptest.NewServer(SetupServer())
   defer ts.Close()
   resp, err := http.Get(fmt.Sprintf("%s/", ts.URL))
   defer resp.Body.Close()

   assert.Nil(t, err)
   assert.Equal(t, http.StatusOK, resp.StatusCode)
   responseData, _ := ioutil.ReadAll(resp.Body)
   assert.Equal(t, mockUserResp, string(responseData))
}

go test执行结果和前面一样的。

为特定Handler写测试用例

假设你的代码里面有自己API路由及其处理程序,如下所示:

func main() {
   router := gin.Default()
   router.POST("/recipes", NewRecipeHandler)
   router.GET("/recipes", ListRecipesHandler)
   router.PUT("/recipes/:id", UpdateRecipeHandler)
   router.DELETE("/recipes/:id", DeleteRecipeHandler)
   router.GET("/recipes/:id", GetRecipeHandler)
   router.Run()
}

GET请求处理程序单元测试

下面以ListRecipesHandler处理程序为例写单元测试:

//为测试使用创建 *gin.Engine实例
func SetupRouter() *gin.Engine {
   router := gin.Default()
   return router
}
func TestListRecipesHandler(t *testing.T) {
   r := SetupRouter()
   //将项目中的API注册到测试使用的router
   r.GET("/recipes", ListRecipesHandler)
   //向注册的路有发起请求
   req, _ := http.NewRequest("GET", "/recipes", nil)
   w := httptest.NewRecorder()
   //模拟http服务处理请求
   r.ServeHTTP(w, req)

   var recipes []Recipe
   json.Unmarshal([]byte(w.Body.String()), &recipes)
   assert.Equal(t, http.StatusOK, w.Code)
   assert.Equal(t, 492, len(recipes))
}

POST请求处理程序单元测试

func TestNewRecipeHandler(t *testing.T) {
   r := SetupRouter()
   r.POST("/recipes", NewRecipeHandler)
   //创建post请求体
   recipe := Recipe{
       Name: "New York Pizza",
   }
   //序列化请求体
   jsonValue, _ := json.Marshal(recipe)
   //发起post请求
   req, _ := http.NewRequest("POST", "/recipes", bytes.NewBuffer(jsonValue))
   w := httptest.NewRecorder()
   r.ServeHTTP(w, req)
   assert.Equal(t, http.StatusOK, w.Code)
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容