分享
  1. 首页
  2. 文章

Golang 项目中如何对 API 进行测试?

掘金 · · 4614 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本文首发于我的博客

简述

在日常后端业务开发中,我们经常会写一些 api,然后用 postman 测试下是否可用,可能就直接丢到线上去了。 然鹅这样做非常不严谨, 大部分情况下还是需要对 api 进行测试,以保证可用性。 我在项目中用到的是 httpexpect, 跟 nodejs 中的 mocha 有一些类似。在这里就不对基本的单元测试做介绍了,大家翻翻 golang 入门指南之类的文档就能看到。

使用

httpexpect 是一个端对端 api 测试工具

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

安装

go get -u -v github.com/gavv/httpexpect

一个小例子

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 数据校验

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

当然也支持其他场景的测试, 比如

  • 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 的例子。

  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/*

有疑问加站长微信联系(非本文作者)

本文来自:掘金

感谢作者:掘金

查看原文:Golang 项目中如何对 API 进行测试?

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
4614 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏