golang路由框架API接口测试插件库gofight的使用

Golang路由框架API接口测试插件库gofight的使用

简介

Gofight是一个用于Golang Web框架的API处理程序测试库,支持多种流行的Golang Web框架。

支持的框架

  • Http Handler (Golang标准库net/http)
  • Gin框架
  • Echo框架 (v3.0.0及以上版本)
  • Mux框架

安装

下载该包:

go get github.com/appleboy/gofight/v2

在代码中导入:

import "github.com/appleboy/gofight/v2"

使用示例

基本Hello World测试

主程序:

package main

import (
  "io"
  "net/http"
)

func BasicHelloHandler(w http.ResponseWriter, r *http.Request) {
  io.WriteString(w, "Hello World")
}

func BasicEngine() http.Handler {
  mux := http.NewServeMux()
  mux.HandleFunc("/", BasicHelloHandler)

  return mux
}

测试代码:

package main

import (
  "net/http"
  "testing"

  "github.com/appleboy/gofight/v2"
  "github.com/stretchr/testify/assert"
)

func TestBasicHelloWorld(t *testing.T) {
  r := gofight.New()

  r.GET("/").
    // 开启调试模式
    SetDebug(true).
    Run(BasicEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
      assert.Equal(t, "Hello World", r.Body.String())
      assert.Equal(t, http.StatusOK, r.Code)
    })
}

设置Header

可以使用SetHeader函数添加自定义Header:

func TestBasicHelloWorld(t *testing.T) {
  r := gofight.New()
  version := "0.0.1"

  r.GET("/").
    // 开启调试模式
    SetDebug(true).
    SetHeader(gofight.H{
      "X-Version": version,
    }).
    Run(BasicEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
      assert.Equal(t, version, rq.Header.Get("X-Version"))
      assert.Equal(t, "Hello World", r.Body.String())
      assert.Equal(t, http.StatusOK, r.Code)
    })
}

提交表单数据

使用SetForm生成表单数据:

func TestPostFormData(t *testing.T) {
  r := gofight.New()

  r.POST("/form").
    SetForm(gofight.H{
      "a": "1",
      "b": "2",
    }).
    Run(BasicEngine(), func(r HTTPResponse, rq HTTPRequest) {
      data := []byte(r.Body.String())

      a, _ := jsonparser.GetString(data, "a")
      b, _ := jsonparser.GetString(data, "b")

      assert.Equal(t, "1", a)
      assert.Equal(t, "2", b)
      assert.Equal(t, http.StatusOK, r.Code)
    })
}

提交JSON数据

使用SetJSON生成JSON数据:

func TestPostJSONData(t *testing.T) {
  r := gofight.New()

  r.POST("/json").
    SetJSON(gofight.D{
      "a": 1,
      "b": 2,
    }).
    Run(BasicEngine, func(r HTTPResponse, rq HTTPRequest) {
      data := []byte(r.Body.String())

      a, _ := jsonparser.GetInt(data, "a")
      b, _ := jsonparser.GetInt(data, "b")

      assert.Equal(t, 1, int(a))
      assert.Equal(t, 2, int(b))
      assert.Equal(t, http.StatusOK, r.Code)
      assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
    })
}

提交原始数据

使用SetBody生成原始数据:

func TestPostRawData(t *testing.T) {
  r := gofight.New()

  r.POST("/raw").
    SetBody("a=1&b=1").
    Run(BasicEngine, func(r HTTPResponse, rq HTTPRequest) {
      data := []byte(r.Body.String())

      a, _ := jsonparser.GetString(data, "a")
      b, _ := jsonparser.GetString(data, "b")

      assert.Equal(t, "1", a)
      assert.Equal(t, "2", b)
      assert.Equal(t, http.StatusOK, r.Code)
    })
}

设置查询字符串

使用SetQuery生成查询字符串:

func TestQueryString(t *testing.T) {
  r := gofight.New()

  r.GET("/hello").
    SetQuery(gofight.H{
      "a": "1",
      "b": "2",
    }).
    Run(BasicEngine, func(r HTTPResponse, rq HTTPRequest) {
      assert.Equal(t, http.StatusOK, r.Code)
    })
}

设置Cookie

使用SetCookie设置Cookie:

func TestQueryString(t *testing.T) {
  r := gofight.New()

  r.GET("/hello").
    SetCookie(gofight.H{
      "foo": "bar",
    }).
    Run(BasicEngine, func(r HTTPResponse, rq HTTPRequest) {
      assert.Equal(t, http.StatusOK, r.Code)
      assert.Equal(t, "foo=bar", rq.Header.Get("cookie"))
    })
}

设置JSON结构体

type User struct {
  // Username 用户名
  Username string `json:"username"`
  // Password 账户密码
  Password string `json:"password"`
}

func TestSetJSONInterface(t *testing.T) {
  r := New()

  r.POST("/user").
    SetJSONInterface(User{
      Username: "foo",
      Password: "bar",
    }).
    Run(framework.GinEngine(), func(r HTTPResponse, rq HTTPRequest) {
      data := []byte(r.Body.String())

      username := gjson.GetBytes(data, "username")
      password := gjson.GetBytes(data, "password")

      assert.Equal(t, "foo", username.String())
      assert.Equal(t, "bar", password.String())
      assert.Equal(t, http.StatusOK, r.Code)
      assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
    })
}

上传多个文件

路由处理程序(Gin框架):

func gintFileUploadHandler(c *gin.Context) {
  ip := c.ClientIP()
  hello, err := c.FormFile("hello")
  if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{
      "error": err.Error(),
    })
    return
  }

  helloFile, _ := hello.Open()
  helloBytes := make([]byte, 6)
  helloFile.Read(helloBytes)

  world, err := c.FormFile("world")
  if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{
      "error": err.Error(),
    })
    return
  }

  worldFile, _ := world.Open()
  worldBytes := make([]byte, 6)
  worldFile.Read(worldBytes)

  foo := c.PostForm("foo")
  bar := c.PostForm("bar")
  c.JSON(http.StatusOK, gin.H{
    "hello":     hello.Filename,
    "world":     world.Filename,
    "foo":       foo,
    "bar":       bar,
    "ip":        ip,
    "helloSize": string(helloBytes),
    "worldSize": string(worldBytes),
  })
}

测试代码:

func TestUploadFile(t *testing.T) {
  r := New()

  r.POST("/upload").
    SetDebug(true).
    SetFileFromPath([]UploadFile{
      {
        Path: "./testdata/hello.txt",
        Name: "hello",
      },
      {
        Path: "./testdata/world.txt",
        Name: "world",
      },
    }, H{
      "foo": "bar",
      "bar": "foo",
    }).
    Run(framework.GinEngine(), func(r HTTPResponse, rq HTTPRequest) {
      data := []byte(r.Body.String())

      hello := gjson.GetBytes(data, "hello")
      world := gjson.GetBytes(data, "world")
      foo := gjson.GetBytes(data, "foo")
      bar := gjson.GetBytes(data, "bar")
      ip := gjson.GetBytes(data, "ip")
      helloSize := gjson.GetBytes(data, "helloSize")
      worldSize := gjson.GetBytes(data, "worldSize")

      assert.Equal(t, "world\n", helloSize.String())
      assert.Equal(t, "hello\n", worldSize.String())
      assert.Equal(t, "hello.txt", hello.String())
      assert.Equal(t, "world.txt", world.String())
      assert.Equal(t, "bar", foo.String())
      assert.Equal(t, "foo", bar.String())
      assert.Equal(t, "", ip.String())
      assert.Equal(t, http.StatusOK, r.Code)
      assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
    })
}

许可证

Copyright 2019 Bo-Yi Wu @appleboy.

根据MIT许可证授权。


更多关于golang路由框架API接口测试插件库gofight的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang路由框架API接口测试插件库gofight的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GoFight - Golang路由框架API接口测试插件库使用指南

GoFight是一个专门为Golang路由框架设计的API接口测试插件库,它可以帮助开发者方便地对基于Gin、Echo等流行框架开发的API进行测试。

安装

go get -u github.com/appleboy/gofight

基本使用

测试Gin框架API

package main

import (
	"net/http"
	"testing"

	"github.com/appleboy/gofight"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
)

func setupGinRouter() *gin.Engine {
	gin.SetMode(gin.TestMode)
	r := gin.New()

	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "welcome",
		})
	})

	r.POST("/login", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")

		if username == "admin" && password == "123456" {
			c.JSON(http.StatusOK, gin.H{
				"status": "logged in",
			})
			return
		}

		c.JSON(http.StatusUnauthorized, gin.H{
			"status": "unauthorized",
		})
	})

	return r
}

func TestGinHelloWorld(t *testing.T) {
	r := setupGinRouter()
	g := gofight.New()

	g.GET("/").
		SetDebug(true).
		Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			assert.Equal(t, http.StatusOK, r.Code)
			assert.Equal(t, "{\"message\":\"welcome\"}", r.Body.String())
		})
}

func TestGinLogin(t *testing.T) {
	r := setupGinRouter()
	g := gofight.New()

	g.POST("/login").
		SetForm(gofight.H{
			"username": "admin",
			"password": "123456",
		}).
		Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			assert.Equal(t, http.StatusOK, r.Code)
			assert.Equal(t, "{\"status\":\"logged in\"}", r.Body.String())
		})

	g.POST("/login").
		SetForm(gofight.H{
			"username": "admin",
			"password": "wrong",
		}).
		Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			assert.Equal(t, http.StatusUnauthorized, r.Code)
			assert.Equal(t, "{\"status\":\"unauthorized\"}", r.Body.String())
		})
}

测试Echo框架API

package main

import (
	"net/http"
	"testing"

	"github.com/appleboy/gofight"
	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
)

func setupEchoRouter() *echo.Echo {
	e := echo.New()

	e.GET("/", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{
			"message": "welcome",
		})
	})

	e.POST("/login", func(c echo.Context) error {
		username := c.FormValue("username")
		password := c.FormValue("password")

		if username == "admin" && password == "123456" {
			return c.JSON(http.StatusOK, map[string]string{
				"status": "logged in",
			})
		}

		return c.JSON(http.StatusUnauthorized, map[string]string{
			"status": "unauthorized",
		})
	})

	return e
}

func TestEchoHelloWorld(t *testing.T) {
	e := setupEchoRouter()
	g := gofight.New()

	g.GET("/").
		SetDebug(true).
		Run(e, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			assert.Equal(t, http.StatusOK, r.Code)
			assert.Equal(t, "{\"message\":\"welcome\"}\n", r.Body.String())
		})
}

func TestEchoLogin(t *testing.T) {
	e := setupEchoRouter()
	g := gofight.New()

	g.POST("/login").
		SetForm(gofight.H{
			"username": "admin",
			"password": "123456",
		}).
		Run(e, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			assert.Equal(t, http.StatusOK, r.Code)
			assert.Equal(t, "{\"status\":\"logged in\"}\n", r.Body.String())
		})
}

高级功能

设置请求头

g.GET("/protected").
	SetHeader(gofight.H{
		"Authorization": "Bearer abc123",
	}).
	Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
		// 测试逻辑
	})

发送JSON请求体

g.POST("/api/users").
	SetJSON(gofight.H{
		"name":  "John Doe",
		"email": "john@example.com",
	}).
	Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
		// 测试逻辑
	})

测试文件上传

g.POST("/upload").
	SetFile(gofight.H{
		"file": "testdata/gofight.txt",
	}).
	Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
		// 测试逻辑
	})

测试查询参数

g.GET("/search").
	SetQuery(gofight.H{
		"q":     "golang",
		"limit": "10",
	}).
	Run(r, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
		// 测试逻辑
	})

优势特点

  1. 简单易用:API设计简洁,学习成本低
  2. 多框架支持:支持Gin、Echo等多种流行Golang路由框架
  3. 功能全面:支持GET、POST、PUT、DELETE等多种HTTP方法
  4. 调试方便:提供SetDebug方法方便调试
  5. 类型安全:使用gofight.H类型确保参数类型安全

GoFight是Golang API测试的一个轻量级解决方案,特别适合在开发过程中快速验证API接口的正确性。它能够与标准testing包无缝集成,是Golang开发者工具箱中的一个实用工具。

回到顶部