软件测试学习——测试工具学习
前言
这一阵子主要工作集中在 MIT6.824 分布式系统理论方面的学习,集中用 go 语言做了两个大实验,本着一学多用的态度,这次测试工具的学习是 go 语言相关(后续学习 C++测试框架 googleTest)。
golang race 检测工具
什么是 race
多线程(Threads、Goroutine)程序对共享变量变量的修改是复杂的,以n=n+1
指令的并行执行为例,如果 t1 和 t2 线程几乎同时取出原始 n 值,在各自线程中完成+1 操作然后储存进变量 n,得到的答案可能并非编程人员想要看到的。
事实上,在上述例子中,我们希望每个线程对共享变量 n 的操作都是有效的,但由于 t1 和 t2 线程几乎同时“看到”n 变量,读取值相同,两次累加从结果看变成了一次累加。
race 的名字变源自于此,这种对共享变量不恰当的操作看起来像像线程间的“赛跑”。 结果是否正确取决于晚些执行到该指令的线程 t2 能否“看到” 先行抵达的线程 t1 的修改(t1 线程执行累加后的变量值)。
race 预防与检测
Go 语言提供的锁机制(mu.lock() mu.unlock())可以帮助我们“锁住”赛跑中的线程,对共享变量加锁是预防 race 出现的常用方式,但是这需要编程人员进行准确细致的编程。不过往往人也有疏忽的时候,可喜的是,golang 在 1.1 之后引入了竞争检测的概念。我们可以使用 go run -race
或者 go build -race
来进行竞争检测。
测试代码 1
1 |
|
运行指令go run -race
,进行 race 检测,如下图
发现了 race,但是由于写回操作较快,没有影响最终结果。
取消time.Sleep
所在行的注释,再次运行指令go run -race
,运行结果如下图
发现了 race,且这次由于线程写回前休眠,所有线程都在其余线程写回前读,所以最终结果被影响。
golang goconvey 测试框架
GoConvey 是一个开源的 go 语言测试工具,实际上 go 本身提供了go test
测试指令供开发者使用,在目录下使用该指令会对该目录中所有后缀为*_test.go
进行测试编译,并对前缀为Test*
的函数进行单元检测。
GoConvey 主要是编写并集成好了一些常用的测试语句(如形式、数值断言等),并提供了一个优秀的可视化界面。
框架安装
由于大陆内部使用 go 语言存在一些限制,而且如果启用GO111MODULE
,我需要大幅度调整我的项目格式,所以我没有采用 mod,也没有按照官方建议的go get
安装方式。
安装好二进制后,我手动检查了依赖项,并在项目源码\src\github.com
分别 clone 几个代码仓库
1 |
|
启动 Web 服务
1 |
|
显示界面如下图,成功。
编写测试代码
- 待检测程序 student.go
1 |
|
- 测试程序 student_test.go
1 |
|
执行测试
VSCode 单元测试结果(go test 命令行)
由于有一个 Error 预期和 nil 实际类型不符合,测试不通过。
Web UI
同样显示有一个 Error 预期和 nil 实际类型不符合,测试不通过。从结构看,5 个断言,通过 4 个,断言处在哪个测试函数中也清晰明了。极大方便了我们排查缺陷所在。另一个简单程序的测试通过情况如下。
结语
通过本次阶段性学习,我发现了解、熟悉、熟练使用测试工具是三个层次,过去我只停留在了解层面,将测试部分和业务逻辑部分混在一起编写,排错难,测试烦。
进行了go run -race
检测和GoConvey
工具的学习后,我才知道原来语言开发者、开源社区还存在着如此高效的工具,不仅减少了 bug 产生的概率,也减少了 bug 发现后修复,回归的时间,可谓一举多得,感谢老师给了我们这个主动学习领域内各种实用知识的机会。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!