前言
上一篇文章说到我还开发了一个独立的自动测试工具,可以根据 openapi 的文档来测试,并且在测试完成后输出测试报告,报告内容包括每个接口是否测试通过和响应时间等。
这个工具我使用了 go 语言开发,主要是考虑到了 go 语言可以傻瓜式的实现交叉编译,生成的可执行文件直接上传到服务器就可以执行,非常方便。
ps: go 语言写起来是真的折磨!感觉语法有很多别扭的地方,不过 build 的时候实在太爽了,根本无法拒绝
为了避免篇幅太长,本文先介绍用到的组件,详细实现以及解析 openapi 文档生成测试配置的部分后续的文章再介绍。
网络请求
标准库中的 net/http
包提供了发送 http 请求的功能,拿到数据之后,使用 json.unmarshal
函数解析 json 数据。这个包相对比较低级,对于简单的网络请求,够用,不过我还是想选择更好用的组件。
resty 是一个简单而强大的 go http 客户端,具有链式 api,可以轻松地发送 http 请求并处理 json 数据。它提供了丰富的功能,包括自动重试、超时设置、请求和响应日志等。您可以使用 resty 来发送 get、post、put、delete 等各种类型的请求,并且它能够自动将响应的 json 数据解析为 go 结构体。
现在出了 v2 版本,支持 http/2、websocket、cookie 操作,并提供了更加简洁和易用的 api 。
项目地址: https://github.com/go-resty/resty
使用起来还行
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
的参数是 interface{}
类型,可以传入的类型比较丰富,我这里还是跟 get 一样传了字典,实际上应该传 struct
比较多一些吧。
日志组件
我之前用的是 go 语言内置的 log ,但似乎功能很少,也没有日志等级啥的,这能叫日志库吗……
接着我找到了在 github 上 star 很多的 logrus 库,不过感觉这是一个比较古老的库了,不太好用,formatter 也没找到好用的,看项目主页的介绍发现这个库已经进入退休状态…
它让我 check out, for example, zerolog, zap, 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...).
项目地址: https://github.com/sirupsen/logrus
所以,最终还是用了 uber 的日志库 go.uber.org/zap
logrus 使用 & 配置
虽然后面换了 zap ,还是记录一下关于 logrus 的使用。
项目主页上列举的几个第三方 formatter 我基本都试用了,就这个 nested-logrus-formatter
比较好用。
以下配置实现了同时输出日志到控制台和文件。
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{}) // 创建一个文件作为日志输出 file, err := os.openfile("logfile.log", os.o_create|os.o_wronly|os.o_append, 0666) if err != nil { logger.fatalf("无法打开日志文件: %v", err) } // 创建一个多写入器,将日志同时输出到控制台和文件 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 好用多了,开箱即用,搭配 zapcore 可以配置多个输出,也可以设置按日志大小分割文件,还可以对接其他日志收集平台啥的,基本做到了现代日志组件的水平了…
一样是实现了同时输出日志到控制台和文件。
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
项目地址: https://github.com/go-swagger/go-swagger
这个可以使用 scoop 安装
scoop install go-swagger
用着一般,没有 swagger code generator 好用。
就没继续探索下去了。
ps: jetbrains 系的 ide 里有几成 swagger code generator 工具,功能非常强大,可以生成各种代码。
不过我还是自己实现了openapi 文档解析(比较灵活),所以暂时还没用上这个强大的工具。
excel 导出
excel 操作我用的是这个 github.com/xuri/excelize/v2
一开始没注意,后面发现这个居然是奇安信开源的…… 然后看了 qax-os 这个 group ,发现开源的几个项目都是跟安全无关的,不务正业啊老哥!
没有对比其他的,看着 star 挺多,上手就直接用了
感觉还行。
func exporttestreportstoexcel(testreports []*tester.report, filename string) error { // 创建一个新的 excel 文件 f := excelize.newfile() // 创建一个名为 "测试报告" 的工作表 index, err := f.newsheet("测试报告") if err != nil { return err } // 设置工作表列名 f.setcellvalue("测试报告", "a1", "接口名称") f.setcellvalue("测试报告", "b1", "接口路径") f.setcellvalue("测试报告", "c1", "测试是否通过") f.setcellvalue("测试报告", "d1", "耗时(秒)") // 遍历测试报告并在工作表中写入数据 for i, report := range testreports { row := i + 2 f.setcellvalue("测试报告", fmt.sprintf("a%d", row), report.apiname) f.setcellvalue("测试报告", fmt.sprintf("b%d", row), report.apipath) f.setcellvalue("测试报告", fmt.sprintf("c%d", row), func() string { if report.ispassed { return "是" } return "否" }()) f.setcellvalue("测试报告", fmt.sprintf("d%d", row), report.elapsed.seconds()) } // 设置活动工作表 f.setactivesheet(index) // 将 excel 文件保存到磁盘 err = f.saveas(filename) if err != nil { return err } return nil }
吐槽
三元表达式
我很想吐槽 go 为啥没有三元表达式,用匿名函数真的好繁琐啊!!
据说是因为觉得三元表达式可以写出很多让人看不懂的骚代码,所以 go 不打算支持,因噎废食啊
不过这难不倒我,可以写个函数来模拟,而且现在 go 似乎更新了泛型的功能,不用再拿 interface 来模拟
func if[t any](condition bool, trueval, falseval t) t { if condition { return trueval } return falseval }
使用的时候就
result := if[string](report.ispassed, "成功", "没通过")
支持类型推导,所以 [string]
也可以省略了。
这样前面导出 excel 的代码里的匿名函数就可以改成这样,简洁多了!
f.setcellvalue("测试报告", fmt.sprintf("c%d", row), if(report.ispassed, "是", "否"))
数组排序
本来也不算什么吐槽,属于是挑刺了,go 的排序没那么好用,但也不难用。
用匿名函数可以实现按字段排序,这倒是和 c 语言里用函数指针大同小异,不愧是带 gc 的 c 语言
测试报告的数据结构是这样
// report 测试报告 type report struct { apiname string apipath string ispassed bool elapsed time.duration response *apiresponse }
我想对 []*report
数组排序,可以用 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);
小结
就这样吧,很简单的一个小工具,因为还处在 go 的小白阶段,每用一个新的库都会记录一下。
参考资料
uber的go日志库zap使用详解 -golang日志操作库zap的使用详解
以上就是使用go语言开发自动化api测试工具详解的详细内容,更多关于go自动化api测试工具的资料请关注代码网其它相关文章!
发表评论