使用go test框架驱动的自动化测试

一. 背景

团队的测试人员稀缺,无奈只能“自己动手,丰衣足食”,针对我们开发的系统进行自动化测试,这样既节省的人力,又提高了效率,还增强了对系统质量保证的信心

我们的目标是让自动化测试覆盖三个环境,如下图所示:

265db351770223e5275dd10929fd5c18.png

我们看到这三个环境分别是:

  • CI/CD流水线上的自动化测试

  • 发版后在各个stage环境中的自动化冒烟/验收测试[1]

  • 发版后在生产环境的自动化冒烟/验收测试

我们会建立统一的用例库或针对不同环境建立不同用例库,但这些都不重要,重要的是我们用什么语言来编写这些用例、用什么工具来驱动这些用例

下面看看方案的诞生过程。

二. 方案

最初组内童鞋使用了YAML文件[2]来描述测试用例,并用Go编写了一个独立的工具读取这些用例并执行。这个工具运作起来也很正常。但这样的方案存在一些问题:

  • 编写复杂

编写一个最简单的connect连接成功的用例,我们要配置近80行yaml。一个稍微复杂的测试场景,则要150行左右的配置。

  • 难于扩展

由于最初的YAML结构设计不足,缺少了扩展性,使得扩展用例时,只能重新建立一个用例文件。

  • 表达能力不足

我们的系统是消息网关,有些用例会依赖一定的时序,但基于YAML编写的用例无法清晰地表达出这种用例。

  • 可维护性差

如果换一个人来编写新用例或维护用例,这个人不仅要看明白一个个百十来行的用例描述,还要翻看一下驱动执行用例的工具,看看其执行逻辑。很难快速cover这个工具。

为此我们想重新设计一个工具,测试开发人员可以利用该工具支持的外部DSL文法[3]来编写用例,然后该工具读取这些用例并执行。

注:根据Martin Fowler的《领域特定语言》[4]一书对DSL的分类,DSL有三种选型:通用配置文件(xml, json, yaml, toml)、自定义领域语言,这两个合起来称为外部DSL。如:正则表达式、awk, sql、xml等。利用通用编程语言片段/子集作为DSL则称为内部dsl,像ruby等。

后来基于待测试的场景数量和用例复杂度粗略评估了一下DSL文法(甚至借助ChatGPT生成过几版DSL文法),发现这个“小语言”那也是“麻雀虽小五脏俱全”。如果用这样的DSL编写用例,和利用通用语言(比如Python)编写的用例在代码量级上估计也不相上下了。

既然如此,自己设计外部DSL意义也就不大了。还不如用Python来整。但转念一想,既然用通用语言的子集了,团队成员对Python又不甚熟悉,那为啥不回到Go呢^_^。

让我们进行一个大胆的设定:将Go testing框架作为“内部DSL”来编写用例,用go test命令作为执行这些用例的测试驱动工具。此外,有了GPT-4加持,生成TestXxx、补充用例啥的应该也不是大问题。

下面我们来看看如何组织和编写用例并使用go test驱动进行自动化测试。

三. 实现

1. 测试用例组织

我的《Go语言精进之路vol2》[5]书中的第41条“有层次地组织测试代码”[6]中对基于go test的测试用例组织做过系统的论述。结合Go test提供的TestMain[7]、TestXxx与sub test[8],我们完全可以基于go test建立起一个层次清晰的测试用例结构。这里就以一个对开源mqtt broker的自动化测试为例来说明一下。

注:你可以在本地搭建一个单机版的开源mqtt broker服务作为被测对象,比如使用Eclipse的mosquitto[9]

在组织用例之前,我先问了一下ChatGPT对一个mqtt broker测试都应该包含哪些方面的用例,ChatGPT给了我一个简单的表:

1fe125dd04a23186df535fb7eb5f2087.png

如果你对MQTT协议[10]有所了解,那么你应该觉得ChatGPT给出的答案还是很不错的。

这里我们就以connection、subscribe和publish三个场景(scenario)来组织用例:

$tree -F .
.
├── Makefile
├── go.mod
├── go.sum
├── scenarios/
│   ├── connection/              // 场景:connection
│   │   ├── connect_test.go      // test suites
│   │   └── scenario_test.go
│   ├── publish/                 // 场景:publish
│   │   ├── publish_test.go      // test suites
│   │   └── scenario_test.go
│   ├── scenarios.go             // 场景中测试所需的一些公共函数
│   └── subscribe/               // 场景:subscribe
│       ├── scenario_test.go     
│       └── subscribe_test.go    // test suites
└── test_report.html             // 生成的默认测试报告

简单说明一下这个测试用例组织布局:

  • 我们将测试用例分为多个场景(scenario),这里包括connection、subscribe和publish;

  • 由于是由go test驱动,所以每个存放test源文件的目录中都要遵循Go对Test的要求,比如:源文件以_test.go结尾等。

  • 每个场景目录下存放着测试用例文件,一个场景可以有多个_test.go文件。这里设定_test.go文件中的每个TestXxx为一个test suite,而TestXxx中再基于subtest编写用例,这里每个subtest case为一个最小的test case;

  • 每个场景目录下的scenario_test.go,都是这个目录下包的TestMain入口,主要是考虑为所有包传入统一的命令行标志与参数值,同时你也针对该场景设置在TestMain中设置setup和teardown。该文件的典型代码如下:

// github.com/bigwhite/experiments/automated-testing/scenarios/subscribe/scenario_test.gopackage subscribeimport ("flag""log""os""testing"mqtt "github.com/eclipse/paho.mqtt.golang"
)var addr stringfunc init() {flag.StringVar(&addr, "addr", "", "the broker address(ip:port)")
}func TestMain(m *testing.M) {flag.Parse()// setup for this scenariomqtt.ERROR = log.New(os.Stdout, "[ERROR] ", 0)// run this scenario testr := m.Run()// teardown for this scenario// tbd if teardown is neededos.Exit(r)
}

接下来我们再来看看具体测试case的实现。

2. 测试用例实现

我们以稍复杂一些的subscribe场景的测试为例,我们看一下subscribe目录下的subscribe_test.go中的测试suite和cases:

// github.com/bigwhite/experiments/automated-testing/scenarios/subscribe/subscribe_test.gopackage subscribeimport (scenarios "bigwhite/autotester/scenarios""testing"
)func Test_Subscribe_S0001_SubscribeOK(t *testing.T) {t.Parallel() // indicate the case can be ran in parallel modetests := []struct {name  stringtopic stringqos   byte}{{name:  "Case_001: Subscribe with QoS 0",topic: "a/b/c",qos:   0,},{name:  "Case_002: Subscribe with QoS 1",topic: "a/b/c",qos:   1,},{name:  "Case_003: Subscribe with QoS 2",topic: "a/b/c",qos:   2,},}for _, tt := range tests {tt := ttt.Run(tt.name, func(t *testing.T) {t.Parallel() // indicate the case can be ran in parallel modeclient, testCaseTeardown, err := scenarios.TestCaseSetup(addr, nil)if err != nil {t.Errorf("want ok, got %v", err)return}defer testCaseTeardown()token := client.Subscribe(tt.topic, tt.qos, nil)token.Wait()// Check if subscription was successfulif token.Error() != nil {t.Errorf("want ok, got %v", token.Error())}token = client.Unsubscribe(tt.topic)token.Wait()if token.Error() != nil {t.Errorf("want ok, got %v", token.Error())}})}
}func Test_Subscribe_S0002_SubscribeFail(t *testing.T) {
}

这个测试文件中的测试用例与我们日常编写单测并没有什么区别!有一些需要注意的地方是:

  • Test函数命名

这里使用了Test_Subscribe_S0001_SubscribeOK、Test_Subscribe_S0002_SubscribeFail命名两个Test suite。命名格式为:

Test_场景_suite编号_测试内容缩略

之所以这么命名,一来是测试用例组织的需要,二来也是为了后续在生成的Test report中区分不同用例使用。

  • testcase通过subtest呈现

每个TestXxx是一个test suite,而基于表驱动的每个sub test则对应一个test case。

  • test suite和test case都可单独标识为是否可并行执行

通过testing.T的Parallel方法可以标识某个TestXxx或test case(subtest)是否是可以并行执行的。

  • 针对每个test case,我们都调用setup和teardown

这样可以保证test case间都相互独立,互不影响。

3. 测试执行与报告生成

设计完布局,编写完用例后,接下来就是执行这些用例。那么怎么执行这些用例呢?

前面说过,我们的方案是基于go test驱动的,我们的执行也要使用go test。

在顶层目录automated-testing下,执行如下命令:

$go test ./... -addr localhost:30083

go test会遍历执行automated-testing下面每个包的测试,在执行每个包的测试时会将-addr这个flag传入。如果localhost:30083端口并没有mqtt broker服务监听,那么上面的命令将输出如下信息:

$go test ./... -addr localhost:30083
?    bigwhite/autotester/scenarios [no test files]
[ERROR] [client]   dial tcp [::1]:30083: connect: connection refused
[ERROR] [client]   Failed to connect to a broker
--- FAIL: Test_Connection_S0001_ConnectOKWithoutAuth (0.00s)connect_test.go:20: want ok, got network Error : dial tcp [::1]:30083: connect: connection refused
FAIL
FAIL bigwhite/autotester/scenarios/connection 0.015s
[ERROR] [client]   dial tcp [::1]:30083: connect: connection refused
[ERROR] [client]   Failed to connect to a broker
--- FAIL: Test_Publish_S0001_PublishOK (0.00s)publish_test.go:11: want ok, got network Error : dial tcp [::1]:30083: connect: connection refused
FAIL
FAIL bigwhite/autotester/scenarios/publish 0.016s
[ERROR] [client]   dial tcp [::1]:30083: connect: connection refused
[ERROR] [client]   dial tcp [::1]:30083: connect: connection refused
[ERROR] [client]   Failed to connect to a broker
[ERROR] [client]   Failed to connect to a broker
[ERROR] [client]   dial tcp [::1]:30083: connect: connection refused
[ERROR] [client]   Failed to connect to a broker
--- FAIL: Test_Subscribe_S0001_SubscribeOK (0.00s)--- FAIL: Test_Subscribe_S0001_SubscribeOK/Case_002:_Subscribe_with_QoS_1 (0.00s)subscribe_test.go:39: want ok, got network Error : dial tcp [::1]:30083: connect: connection refused--- FAIL: Test_Subscribe_S0001_SubscribeOK/Case_003:_Subscribe_with_QoS_2 (0.00s)subscribe_test.go:39: want ok, got network Error : dial tcp [::1]:30083: connect: connection refused--- FAIL: Test_Subscribe_S0001_SubscribeOK/Case_001:_Subscribe_with_QoS_0 (0.00s)subscribe_test.go:39: want ok, got network Error : dial tcp [::1]:30083: connect: connection refused
FAIL
FAIL bigwhite/autotester/scenarios/subscribe 0.016s
FAIL

这也是一种测试失败的情况。

在自动化测试时,我们一般会把错误或成功的信息保存到一个测试报告文件(多是html)中,那么我们如何基于上面的测试结果内容生成我们的测试报告文件呢?

首先go test支持将输出结果以结构化的形式展现,即传入-json这个flag。这样我们仅需基于这些json输出将各个字段读出并写入html中即可。好在有现成的开源工具可以做到这点,那就是go-test-report[11]。下面是通过命令行管道让go test与go-test-report配合工作生成测试报告的命令行:

注:go-test-report工具的安装方法:go install github.com/vakenbolt/go-test-report@latest

$go test ./... -addr localhost:30083 -json|go-test-report
[go-test-report] finished in 1.375540542s

执行结束后,就会在当前目录下生成一个test_report.html文件,使用浏览器打开该文件就能看到测试执行结果:

e3f64491de359689c78bf398e33bed43.png

通过测试报告的输出,我们可以很清楚看到哪些用例通过,哪些用例失败了。并且通过Test suite的名字或Test case的名字可以快速定位是哪个scenario下的哪个suite的哪个case报的错误!我们也可以点击某个test suite的名字,比如:Test_Connection_S0001_ConnectOKWithoutAuth,打开错误详情查看错误对应的源文件与具体的行号:

edff17275cf459ca302b6098b452dd63.png

为了方便快速敲入上述命令,我们可以将其放入Makefile中方便输入执行,即在顶层目录下,执行make即可执行测试:

$make
go test ./... -addr localhost:30083 -json|go-test-report
[go-test-report] finished in 2.011443636s

如果要传入自定义的mqtt broker的服务地址,可以用:

$make broker_addr=192.168.10.10:10083

四. 小结

在这篇文章中,我们介绍了如何实现基于go test驱动的自动化测试,介绍了这样的测试的结构布局、用例编写方法、执行与报告生成等。

这个方案的不足是要求测试用例所在环境需要部署go与go-test-report

go test支持将test编译为一个可执行文件,不过不支持将多个包的测试编译为一个可执行文件:

$go test -c ./...
cannot use -c flag with multiple packages

此外由于go test编译出的可执行文件不支持将输出内容转换为JSON格式[12],因此也无法对接go-test-report将测试结果保存在文件中供后续查看。

本文涉及的源码可以在这里[13]下载 - https://github.com/bigwhite/experiments/tree/master/automated-testing


“Gopher部落”知识星球[14]旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2023年,Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码,关注代码质量并深入理解Go核心技术,并继续加强与星友的互动。欢迎大家加入!

74b272bca64837f651776de7a43eabb8.png

e039efd807106eb0229a0d91966049ce.png

b1bd6307ee1668f59c7f0b46cb33989c.png

d80db7f2826e71f850400e3222f331bd.jpeg

Gopher Daily(Gopher每日新闻)归档仓库 - https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx

  • 微博2:https://weibo.com/u/6484441286

  • 博客:tonybai.com

  • github: https://github.com/bigwhite

edaf33ad5a986dcb79af688cc968be54.png

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

参考资料

[1] 

验收测试: http://en.wikipedia.org/wiki/Acceptance_testing

[2] 

YAML文件: https://tonybai.com/2019/02/25/introduction-to-yaml-creating-a-kubernetes-deployment/

[3] 

外部DSL文法: https://tonybai.com/2022/05/10/introduction-of-implement-dsl-using-antlr-and-go

[4] 

《领域特定语言》: https://book.douban.com/subject/21964984/

[5] 

《Go语言精进之路vol2》: https://item.jd.com/13694000.html

[6] 

第41条“有层次地组织测试代码”: https://book.douban.com/subject/35720729/

[7] 

TestMain: https://pkg.go.dev/testing#Main

[8] 

sub test: https://tonybai.com/2023/03/15/an-intro-of-go-subtest/

[9] 

Eclipse的mosquitto: https://github.com/eclipse/mosquitto

[10] 

MQTT协议: https://mqtt.org/mqtt-specification/

[11] 

go-test-report: https://github.com/vakenbolt/go-test-report

[12] 

不支持将输出内容转换为JSON格式: https://github.com/golang/go/issues/22996

[13] 

这里: https://github.com/bigwhite/experiments/tree/master/automated-testing

[14] 

“Gopher部落”知识星球: https://wx.zsxq.com/dweb2/index/group/51284458844544

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/45124.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知乎大模型「知海图AI」上线!产品官宣即内测,为4亿用户摘取「热榜摘要」...

杨净 发自 凹非寺量子位 | 公众号 QbitAI 又一家国内企业大模型产品发布。 不是别的,而是已拥有4亿用户的最大中文问答社区知乎。 而且官宣即内测—— 不光有首个大语言模型「知海图AI」,首款产品也将应用于热榜。 情理之中,意料之外。 一方面…

3月4月琐碎但值得的事

很多小伙伴应该发现最近我异常忙,忙到3月总结都没有写,忙到每天睡3-4个小时, 结果一拖到5月了, 索性3,4月小结一起写了,仅仅代表我个人观点,不一定对,如果有帮助最好了。 有兴趣可以…

最新人工智能GPT-4免费简单使用教程

GPT-4比Chatgpt升级了不少,现在还无法使用OpenAI官网或百度文心一言的小伙伴可以尝试以下方法。 打开 nat.dev 登录(sign-in注册时不用填手机号码) 选择GPT-4模型 然后直接空白处用英语或者中文输入问题 想尝试AI作图的方法如下。 打开网页…

中文邮件格式模板、工作汇报邮件模板这样写,90%人都爱看

时常收发邮件的人都知道,邮件书写格式是一件很讲究的事,所以大家都要掌握基本的邮件格式模板。 如何书写一份得体的邮件? 原则:有礼貌、讲重点、条理清晰 称呼:通常根据职位来称呼,xx经理、xx总、xx老师 …

BUILD AN LLM-POWERED APPLICATION USING LANGCHAIN: A COMPREHENSIVE STEP-BY-STEP GUIDE

目录 Introduction to LangChain and LLM-powered applications LangChain: Its components and working Launch your project with LeewayHertz Different types of models that are used in LangChain

吐血整理| 30+款实用谷歌Chrome插件大合集

让我看看都2023年了,谁还在用谷歌浏览器不安装插件?? 插件是浏览器的外展功能,安装后可以实现各种浏览器自带功能不能实现的很多操作,在本篇文章中,本小白为大家吐血整理出了30款好用的Chrome插件&#xf…

从 ELMo 到 ChatGPT:历数 NLP 近 5 年必看大模型

目录 AI21 LabsAlibabaAllen Institute for AIAmazonAnthropicBAAIBaiduBigScienceCohereDeepMindEleutherAIGoogleHuggingfaceiFLYTEKMeta (Facebook)MicrosoftNVidiaOpenAISalesforceTsinghua UniversityUC BerkeleyYandex持续更新中 ...参考 团队博客: CSDN AI小组 相关阅读…

Adobe全新AI工具引关注,Adobe firefly助力创作更高效、更有创意

原标题:Adobe全新AI工具引关注,Adobe firefly(萤火虫)助力创作更高效、更有创意。 以ChatGPT为首的生成式AI、AIGC等工具的战局正如火如荼的进行中..... 除了微软、百度的聊天机器人和一些初创公司的AI画图工具令人惊艳&#xff…

李飞飞高徒盘点年度十大AI亮点:核聚变、ChatGPT、AlphaFold上榜

来源:新智元 编辑:Aeneas 昕朋 【导读】2022年有哪些人工智能的突破?今天,李飞飞高徒Jim Fan盘点了年度十大AI亮点。 人工智能的爆炸正在扭曲我们的时间感。 你能相信Stable Diffusion只有4个月大,而ChatGPT的出现还不…

【教学类-38】20230724京剧脸谱涂色(Python 彩图彩照转素描线描稿)

一、作品预览 京剧脸谱(涂色)学具展示(64份) 二、背景需求: 1、大班主题《我是中国人》里面有一个“京剧脸谱”的子主题。从网上下载的彩色脸谱(红黄绿蓝紫黑白),作为环境装饰。引…

智能ai生成绘画软件有哪些?亲测好用的软件分享

小伙伴们有听说过ai绘画吗?这是目前比较火的一种绘画方式,我们可以通过给AI输入一段关于画面描述的文字内容,ai就可以根据这些内容,生成一幅相关的画作。对于不会画画,但是有创意的小伙伴,你们会不会也想试…

Drawio免费绘图软件下载

drawio是一款强大、免费的绘图工具,使用起来非常方便,非常好用,可以满足大部分画图功能,例如UML、页面设计(Android&iOS)等visio能画的图它都可以画。支持网页版使用(网页版可以自己部署一套…

ai绘画生成软件哪个好?这3款ai绘画生成软件还不错

你知道ai绘画生成软件哪个好吗?随着人工智能技术的不断进步,AI绘画已经成为了一种极具前瞻性的技术。 在过去的几年中,出现了许多强大的AI绘画工具,如一键AI绘画、梦幻AI画家和Midjourney软件等。这些工具利用机器学习和计算机视觉…

文字生成绘画软件有哪些?推荐你几款好用的ai绘画工具

在社交媒体应用中,文字生成绘画的软件可以使我们更好地记录生活中的美好瞬间,而且它可以把文字内容制作成好看的图片分享给亲朋好友,增强沟通和互动效果。那么,小伙伴们知道文字生成绘画软件有哪些吗?这篇文章就给你推…

推荐几个ai生成绘画软件给你

绘画是一门需要艺术家经过长时间的学习和实践才能精通的技能,但现在有了人工智能绘画软件,人们可以更加轻松地创作出美丽的作品。今天,我们将和大家介绍一下ai绘画软件有哪些,希望这篇文章能够帮助你们实现自己的创意。 推荐电脑端…

ai绘画生成软件哪个好?分享几个ai绘画软件

ai绘画是人工智能技术在绘画领域的应用。随着科学技术的不断发展,越来越多的绘画软件开始采用ai技术,为画家提供更加自由、更加灵活的绘画体验。ai绘画的基本原理是利用人工智能技术对绘画过程进行辅助。在传统的绘画中,艺术家需要通过手工完…

这几个AI生成绘画软件推荐给大家

以前只有专业的画家才能绘制出优秀的画作,但现在AI技术的进步为普通人带来了极大的便利,只需要使用特定的软件,就能轻松绘制出高质量的画作。那大家知道可以AI人工智能绘画的软件有哪些吗?如果不知道也没关系,我来分享几款给你。…

AI绘画怎么生成?这些软件帮助你实现

不知道前段时间,大家的朋友圈会不会出现很多的ai绘画作品呢?这是近期一个深受年轻人喜欢的绘画手法,它主要是通过ai技术,将我们描述的文字以及图片绘制成一幅画。那大家知道ai绘画怎么弄的吗?不知道的没关系&#xff0…

android手机绘图软件,手机绘画软件(MediBang Paint Tablet)

MediBang Paint Tablet 是一款功能丰富的手机绘画软件,主要是用来绘制插画和漫画,内置有丰富的笔刷、素材、漫画用字体等功能,方便动漫作者进行创作,软件还为作者提供了云存储空间,作品可以上传保存,也可以…

AI可以自动生成绘画吗?分享几款AI绘画软件

AI绘画热潮来临之前,我在网上看到不少人发了AI绘画的图片,除了画人物,还有画漫画和风景的图片,画面真实和色彩丰富程度让我不敢相信是AI画的,于是就去网上搜索AI可以自动生成绘画吗?在搜索的过程中&#xf…