Golang 項目中如何對 API 進行測試?

本文首發於個人博客node

簡述

在平常後端業務開發中,咱們常常會寫一些 api,而後用 postman 測試下是否可用,可能就直接丟到線上去了。 然鵝這樣作很是不嚴謹, 大部分狀況下仍是須要對 api 進行測試,以保證可用性。 我在項目中用到的是 httpexpect, 跟 nodejs 中的 mocha 有一些相似。在這裏就不對基本的單元測試作介紹了,你們翻翻 golang 入門指南之類的文檔就能看到。git

使用

httpexpect 是一個端對端 api 測試工具github

End-to-end HTTP and REST API testing for Go.golang

安裝mongodb

go get -u -v github.com/gavv/httpexpect
複製代碼

一個小例子express

package example

import (
  "net/http"
  "net/http/httptest"
  "testing"

  "github.com/gavv/httpexpect"
)

func TestFruits(t *testing.T) {
  // 建立 http.Handler
  handler := FruitsHandler()

  // 運行 server
  server := httptest.NewServer(handler)
  defer server.Close()

  // 建立 httpexpect 實例
  e := httpexpect.New(t, server.URL)

  // 測試api是否工做
  e.GET("/test").
    Expect().
    Status(http.StatusOK).JSON().Array().Empty()
}
複製代碼

支持 json 數據校驗json

orange := map[string]interface{}{
  "weight": 100,
}

//  GET 建立一個橘子
e.PUT("/fruits/orange").WithJSON(orange).
  Expect().
  Status(http.StatusNoContent).NoContent()

// GET 而後獲取, 並校驗數據中是否含有 weight: 100
e.GET("/fruits/orange").
  Expect().
  Status(http.StatusOK).
  JSON().Object().ContainsKey("weight").ValueEqual("weight", 100)

apple := map[string]interface{}{
  "colors": []interface{}{"green", "red"},
  "weight": 200,
}
// 建立一個蘋果
e.PUT("/fruits/apple").WithJSON(apple).
  Expect().
  Status(http.StatusNoContent).NoContent()
// 獲取這個蘋果
obj := e.GET("/fruits/apple").
  Expect().
  Status(http.StatusOK).JSON().Object()

obj.Keys().ContainsOnly("colors", "weight")

// 對 返回數據逐一測試
obj.Value("colors").Array().Elements("green", "red")
obj.Value("colors").Array().Element(0).String().Equal("green")
obj.Value("colors").Array().Element(1).String().Equal("red")
obj.Value("colors").Array().First().String().Equal("green")
obj.Value("colors").Array().Last().String().Equal("red")
複製代碼

鏈式調用函數用起來很順手,其實內置函數還有不少, Object 數據類型有以下函數等等,知足各類測試須要。後端

ContainsKey
ContainsMap
Empty
Equal
Keys
NotContainsKey
複製代碼

固然也支持其餘場景的測試, 好比api

  • JSON Schema and JSON Path JSON 模式
  • Forms 表單
  • URL construction url 構造
  • HTTP Headers header
  • Cookies cookie
  • Regular expressions 正則
  • Subdomains and per-request URL 子 url
  • Reusable builders 可重複使用
  • Custom config 自定義
  • Session support session會話支持
  • Use HTTP handler directly 重定向

實際應用

下面是一個依賴 gin 框架 api 項目使用 httpexpect 的例子。bash

  1. app.go
package main

import (
  "./engine"
)

func main() {
  engine.GetMainEngine().Run(":4000")
}
複製代碼
  1. engine/engine.go, 這裏之因此多一個 engine.go, 是由於咱們要把 *gin.Engine 返回給 httpexpect, 建立 server,參考 node.js 項目 api 測試。
package engine

import (
  "github.com/gin-contrib/sessions"
  "github.com/gin-gonic/gin"
)

func GetMainEngine() *gin.Engine {
  r := gin.New()
  // db, store := database.Connect()
  // logdb := database.ConnectLog()
  // r.Use(sessions.Sessions("xxx", store))
  // r.Use(corsMiddleware())
  // r.Use(gin.Logger())
  // r.Use(gin.Recovery())
  // r.Use(requestLogger())
        // 一堆自定義的 handler
  routers.Init(r)
  return r
}
複製代碼
  1. articles_test.go
package test

import (
  "net/http"
  "testing"
)

var eng *httpexpect.Expect

func GetEngine(t *testing.T) *httpexpect.Expect {
  gin.SetMode(gin.TestMode)
  if eng == nil {
    server := httptest.NewServer(engine.GetMainEngine())
    eng = httpexpect.New(t, server.URL)
  }
  return eng
}

func TestArticles(t *testing.T) {
  e := GetEngine(t)
  e.GET("/api/v1/articles").
    Expect().
    Status(http.StatusOK).
    JSON().Object().ContainsKey("data").Keys().Length().Ge(0)
}

複製代碼

而後執行

go test -v -cover ...
複製代碼

執行結果相似:

執行結果

使用這個包,咱們能夠對 restful 的每一個 api 都進行測試 😀, 更大程度地提高了代碼質量。如下是個人 .travis.yml 配置。 不足之處,請批評指正!

language: go

services: mongodb

go:
 - 1.9.2
 - master

install: true

matrix:
 allow_failures:
 - go: master
 fast_finish: true

notifications:
 email: false

script:
 - echo "script"
 - go get -u -v  github.com/gavv/httpexpect
 - 其餘自定義
 - echo "add config file"
 - cp config/config.example.yaml config/config.yaml
 - echo "test"
 - export GIN_MODE=test
 - go test -v -cover test/*
複製代碼
相關文章
相關標籤/搜索