欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Go語(yǔ)言開(kāi)發(fā)自動(dòng)化API測(cè)試工具詳解

 更新時(shí)間:2024年03月08日 10:58:30   作者:程序設(shè)計(jì)實(shí)驗(yàn)室  
這篇文章主要為大家詳細(xì)介紹了如何使用Go語(yǔ)言開(kāi)發(fā)自動(dòng)化API測(cè)試工具,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下

前言

上一篇文章說(shuō)到我還開(kāi)發(fā)了一個(gè)獨(dú)立的自動(dòng)測(cè)試工具,可以根據(jù) OpenAPI 的文檔來(lái)測(cè)試,并且在測(cè)試完成后輸出測(cè)試報(bào)告,報(bào)告內(nèi)容包括每個(gè)接口是否測(cè)試通過(guò)和響應(yīng)時(shí)間等。

這個(gè)工具我使用了 go 語(yǔ)言開(kāi)發(fā),主要是考慮到了 go 語(yǔ)言可以傻瓜式的實(shí)現(xiàn)交叉編譯,生成的可執(zhí)行文件直接上傳到服務(wù)器就可以執(zhí)行,非常方便。

PS: go 語(yǔ)言寫起來(lái)是真的折磨!感覺(jué)語(yǔ)法有很多別扭的地方,不過(guò) build 的時(shí)候?qū)嵲谔?,根本無(wú)法拒絕

為了避免篇幅太長(zhǎng),本文先介紹用到的組件,詳細(xì)實(shí)現(xiàn)以及解析 OpenAPI 文檔生成測(cè)試配置的部分后續(xù)的文章再介紹。

網(wǎng)絡(luò)請(qǐng)求

標(biāo)準(zhǔn)庫(kù)中的 net/http 包提供了發(fā)送 HTTP 請(qǐng)求的功能,拿到數(shù)據(jù)之后,使用 json.Unmarshal 函數(shù)解析 JSON 數(shù)據(jù)。這個(gè)包相對(duì)比較低級(jí),對(duì)于簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求,夠用,不過(guò)我還是想選擇更好用的組件。

Resty 是一個(gè)簡(jiǎn)單而強(qiáng)大的 Go HTTP 客戶端,具有鏈?zhǔn)?API,可以輕松地發(fā)送 HTTP 請(qǐng)求并處理 JSON 數(shù)據(jù)。它提供了豐富的功能,包括自動(dòng)重試、超時(shí)設(shè)置、請(qǐng)求和響應(yīng)日志等。您可以使用 Resty 來(lái)發(fā)送 GET、POST、PUT、DELETE 等各種類型的請(qǐng)求,并且它能夠自動(dòng)將響應(yīng)的 JSON 數(shù)據(jù)解析為 Go 結(jié)構(gòu)體。

現(xiàn)在出了 v2 版本,支持 HTTP/2、WebSocket、Cookie 操作,并提供了更加簡(jiǎn)潔和易用的 API 。

項(xiàng)目地址: https://github.com/go-resty/resty

使用起來(lái)還行

GET 方法

import 	"github.com/go-resty/resty/v2"

req := c.RestyClient.R().SetHeader("Authorization", "token "+c.AuthToken)

req.SetQueryParams(map[string]string{
  "year":  "2024",
})
resp, err = req.Get("path")

POST 方法

req.SetBody(map[string]string{
  "year":  "2024",
})
resp, err = req.Get("path")

SetBody 的參數(shù)是 interface{} 類型,可以傳入的類型比較豐富,我這里還是跟 GET 一樣傳了字典,實(shí)際上應(yīng)該傳 struct 比較多一些吧。

日志組件

我之前用的是 go 語(yǔ)言內(nèi)置的 log ,但似乎功能很少,也沒(méi)有日志等級(jí)啥的,這能叫日志庫(kù)嗎……

接著我找到了在 GitHub 上 star 很多的 logrus 庫(kù),不過(guò)感覺(jué)這是一個(gè)比較古老的庫(kù)了,不太好用,formatter 也沒(méi)找到好用的,看項(xiàng)目主頁(yè)的介紹發(fā)現(xiàn)這個(gè)庫(kù)已經(jīng)進(jìn)入退休狀態(tài)…

它讓我 Check out, for example, ZerologZap, and Apex.

Logrus is in maintenance-mode. We will not be introducing new features. It's simply too hard to do in a way that won't break many people's projects, which is the last thing you want from your Logging library (again...).

項(xiàng)目地址: https://github.com/sirupsen/logrus

所以,最終還是用了 uber 的日志庫(kù) go.uber.org/zap

logrus 使用 & 配置

雖然后面換了 zap ,還是記錄一下關(guān)于 logrus 的使用。

項(xiàng)目主頁(yè)上列舉的幾個(gè)第三方 formatter 我基本都試用了,就這個(gè) nested-logrus-formatter 比較好用。

以下配置實(shí)現(xiàn)了同時(shí)輸出日志到控制臺(tái)和文件。

import (
  nested "github.com/antonfisher/nested-logrus-formatter"
  "github.com/sirupsen/logrus"
  "os"
)

func initLogger() *os.File {
  logger.SetLevel(logrus.DebugLevel)
  logger.SetReportCaller(true)
  logger.SetFormatter(&nested.Formatter{})

  // 創(chuàng)建一個(gè)文件作為日志輸出
  file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  if err != nil {
    logger.Fatalf("無(wú)法打開(kāi)日志文件: %v", err)
  }

  // 創(chuàng)建一個(gè)多寫入器,將日志同時(shí)輸出到控制臺(tái)和文件
  mw := io.MultiWriter(os.Stdout, file)

  // 添加 Hook 到 Logger 中
  logger.Out = mw

  return file
}

func main() {
  file := initLogger()
  defer func(file *os.File) {
    err := file.Close()
    if err != nil {
      fmt.Println(err)
    }
  }(file)
}

zap 使用 & 配置

zap 比起 logrus 好用多了,開(kāi)箱即用,搭配 zapcore 可以配置多個(gè)輸出,也可以設(shè)置按日志大小分割文件,還可以對(duì)接其他日志收集平臺(tái)啥的,基本做到了現(xiàn)代日志組件的水平了…

一樣是實(shí)現(xiàn)了同時(shí)輸出日志到控制臺(tái)和文件。

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

func buildLogger() *zap.SugaredLogger {
  config := zap.NewProductionEncoderConfig()
  config.EncodeTime = zapcore.ISO8601TimeEncoder
  consoleEncoder := zapcore.NewConsoleEncoder(config)
  fileEncoder := zapcore.NewJSONEncoder(config)
  logFile, _ := os.OpenFile("./log-test-zap.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 06666)

  tee := zapcore.NewTee(
    zapcore.NewCore(fileEncoder, zapcore.AddSync(logFile), zap.DebugLevel),
    zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), zap.DebugLevel),
  )
  var zapLogging = zap.New(
    tee,
    zap.AddCaller(),
    zap.AddStacktrace(zapcore.ErrorLevel),
  )

  var logger = zapLogging.Sugar()
  return logger
}

func main() {
  logger := buildLogger()
  defer logger.Sync()
}

swagger 組件

這里我試著用了一下 go swagger

項(xiàng)目地址: https://github.com/go-swagger/go-swagger

這個(gè)可以使用 scoop 安裝

scoop install go-swagger

用著一般,沒(méi)有 swagger code generator 好用。

就沒(méi)繼續(xù)探索下去了。

PS: Jetbrains 系的 IDE 里有幾成 swagger code generator 工具,功能非常強(qiáng)大,可以生成各種代碼。

不過(guò)我還是自己實(shí)現(xiàn)了OpenAPI 文檔解析(比較靈活),所以暫時(shí)還沒(méi)用上這個(gè)強(qiáng)大的工具。

Excel 導(dǎo)出

Excel 操作我用的是這個(gè) github.com/xuri/excelize/v2

一開(kāi)始沒(méi)注意,后面發(fā)現(xiàn)這個(gè)居然是奇安信開(kāi)源的…… 然后看了 qax-os 這個(gè) group ,發(fā)現(xiàn)開(kāi)源的幾個(gè)項(xiàng)目都是跟安全無(wú)關(guān)的,不務(wù)正業(yè)啊老哥!

沒(méi)有對(duì)比其他的,看著 star 挺多,上手就直接用了

感覺(jué)還行。

func exportTestReportsToExcel(testReports []*tester.Report, filename string) error {
  // 創(chuàng)建一個(gè)新的 Excel 文件
  f := excelize.NewFile()

  // 創(chuàng)建一個(gè)名為 "測(cè)試報(bào)告" 的工作表
  index, err := f.NewSheet("測(cè)試報(bào)告")
  if err != nil {
    return err
  }

  // 設(shè)置工作表列名
  f.SetCellValue("測(cè)試報(bào)告", "A1", "接口名稱")
  f.SetCellValue("測(cè)試報(bào)告", "B1", "接口路徑")
  f.SetCellValue("測(cè)試報(bào)告", "C1", "測(cè)試是否通過(guò)")
  f.SetCellValue("測(cè)試報(bào)告", "D1", "耗時(shí)(秒)")

  // 遍歷測(cè)試報(bào)告并在工作表中寫入數(shù)據(jù)
  for i, report := range testReports {
    row := i + 2
    f.SetCellValue("測(cè)試報(bào)告", fmt.Sprintf("A%d", row), report.ApiName)
    f.SetCellValue("測(cè)試報(bào)告", fmt.Sprintf("B%d", row), report.ApiPath)
    f.SetCellValue("測(cè)試報(bào)告", fmt.Sprintf("C%d", row), func() string {
      if report.IsPassed {
        return "是"
      }
      return "否"
    }())
    f.SetCellValue("測(cè)試報(bào)告", fmt.Sprintf("D%d", row), report.Elapsed.Seconds())
  }

  // 設(shè)置活動(dòng)工作表
  f.SetActiveSheet(index)

  // 將 Excel 文件保存到磁盤
  err = f.SaveAs(filename)
  if err != nil {
    return err
  }

  return nil
}

吐槽

三元表達(dá)式

我很想吐槽 go 為啥沒(méi)有三元表達(dá)式,用匿名函數(shù)真的好繁瑣啊?。?/p>

據(jù)說(shuō)是因?yàn)橛X(jué)得三元表達(dá)式可以寫出很多讓人看不懂的騷代碼,所以 go 不打算支持,因噎廢食啊

不過(guò)這難不倒我,可以寫個(gè)函數(shù)來(lái)模擬,而且現(xiàn)在 go 似乎更新了泛型的功能,不用再拿 interface 來(lái)模擬

func If[T any](condition bool, trueVal, falseVal T) T {
  if condition {
    return trueVal
  }
  return falseVal
}

使用的時(shí)候就

result := If[string](report.IsPassed, "成功", "沒(méi)通過(guò)")

支持類型推導(dǎo),所以 [string] 也可以省略了。

這樣前面導(dǎo)出 Excel 的代碼里的匿名函數(shù)就可以改成這樣,簡(jiǎn)潔多了!

f.SetCellValue("測(cè)試報(bào)告", fmt.Sprintf("C%d", row), If(report.IsPassed, "是", "否"))

數(shù)組排序

本來(lái)也不算什么吐槽,屬于是挑刺了,go 的排序沒(méi)那么好用,但也不難用。

用匿名函數(shù)可以實(shí)現(xiàn)按字段排序,這倒是和 C 語(yǔ)言里用函數(shù)指針大同小異,不愧是帶 gc 的 C 語(yǔ)言

測(cè)試報(bào)告的數(shù)據(jù)結(jié)構(gòu)是這樣

// Report 測(cè)試報(bào)告
type Report struct {
  ApiName  string
  ApiPath  string
  IsPassed bool
  Elapsed  time.Duration
  Response *ApiResponse
}

我想對(duì) []*Report 數(shù)組排序,可以用 sort.Slice 方法

// 按照 Elapsed 屬性排序,從大到小
sort.Slice(testReports, func(i, j int) bool {
  return testReports[i].Elapsed > testReports[j].Elapsed
})

相比之下還是 cs 的 Linq 舒服啊

testReports.Sort((a, b) => a - b);

小結(jié)

就這樣吧,很簡(jiǎn)單的一個(gè)小工具,因?yàn)檫€處在 go 的小白階段,每用一個(gè)新的庫(kù)都會(huì)記錄一下。

參考資料

uber的Go日志庫(kù)zap使用詳解 -Golang日志操作庫(kù)zap的使用詳解

以上就是使用Go語(yǔ)言開(kāi)發(fā)自動(dòng)化API測(cè)試工具詳解的詳細(xì)內(nèi)容,更多關(guān)于Go自動(dòng)化API測(cè)試工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang判斷net.Conn 是否已關(guān)閉的操作

    golang判斷net.Conn 是否已關(guān)閉的操作

    這篇文章主要介紹了golang判斷net.Conn 是否已關(guān)閉的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go語(yǔ)言判斷文件或文件夾是否存在的方法

    Go語(yǔ)言判斷文件或文件夾是否存在的方法

    這篇文章主要介紹了Go語(yǔ)言判斷文件或文件夾是否存在的方法,結(jié)合具體實(shí)例形式對(duì)比分析了Go語(yǔ)言針對(duì)文件與目錄判斷的操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-05-05
  • Golang編譯器介紹

    Golang編譯器介紹

    今天小編就為大家分享一篇關(guān)于go語(yǔ)言編譯器的介紹,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-09-09
  • 基于go interface{}==nil 的幾種坑及原理分析

    基于go interface{}==nil 的幾種坑及原理分析

    這篇文章主要介紹了基于go interface{}==nil 的幾種坑及原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • golang?JSON序列化和反序列化示例詳解

    golang?JSON序列化和反序列化示例詳解

    通過(guò)使用Go語(yǔ)言的encoding/json包,你可以輕松地處理JSON數(shù)據(jù),無(wú)論是在客戶端應(yīng)用、服務(wù)器端應(yīng)用還是其他類型的Go程序中,這篇文章主要介紹了golang?JSON序列化和反序列化,需要的朋友可以參考下
    2024-04-04
  • 特殊字符的json序列化總結(jié)大全

    特殊字符的json序列化總結(jié)大全

    這篇文章主要給大家介紹了關(guān)于特殊字符的json序列化的相關(guān)資料,通過(guò)示例代碼分別給大家介紹了關(guān)于python 、 rust 、 java 和golang對(duì)特殊字符的json序列化操作,需要的朋友可以參考借鑒,下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • go語(yǔ)言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    go語(yǔ)言reflect.Type?和?reflect.Value?應(yīng)用示例詳解

    這篇文章主要為大家介紹了go語(yǔ)言reflect.Type?和?reflect.Value?應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Go1.20最新資訊go?arena手動(dòng)管理內(nèi)存鴿了

    Go1.20最新資訊go?arena手動(dòng)管理內(nèi)存鴿了

    由于過(guò)于繁雜,Go?核心團(tuán)隊(duì)成員@Ian?Lance?Taylor,也表態(tài):目前尚未做出任何決定,也不可能在短期內(nèi)做出任何決定,可以認(rèn)為這個(gè)提案基本鴿了,今天這篇文章就是給大家同步目前的情況
    2023-11-11
  • go kratos源碼及配置解析

    go kratos源碼及配置解析

    這篇文章主要為大家介紹了go kratos源碼及配置解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • GO中公平鎖和非公平鎖的具體使用

    GO中公平鎖和非公平鎖的具體使用

    公平鎖和非公平鎖是計(jì)算機(jī)科學(xué)中的兩種鎖機(jī)制,它們主要用于多線程編程,以控制對(duì)共享資源的訪問(wèn),本文主要介紹了GO中公平鎖和非公平鎖的具體使用,感興趣的可以了解一下
    2024-08-08

最新評(píng)論