GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
- GO语言学习笔记-函数篇 Study for Go ! Chapter three - Function
- GO语言学习笔记-数据篇 Study for Go ! Chapter four - Data
- GO语言学习笔记-方法篇 Study for Go ! Chapter five - Method
- GO语言学习笔记-接口篇 Study for Go ! Chapter six - Interface
- GO语言学习笔记-并发篇 Study for Go ! Chapter seven - Concurrency
- GO语言学习笔记-包结构篇 Study for Go ! Chapter eight - Package Structure
- GO语言学习笔记-反射篇 Study for Go ! Chapter nine - Reflect
- GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
- GO语言学习笔记-工具链篇 Study for Go ! Chapter eleven - Tool Chain
1. 单元测试 ( unit test )
单元测试 ( unit test )除用来测试逻辑算法是否符合预期外,还承担着监控代码质量的责任。任何时候都可以用简单的命令来验证全部功能,找出未完成任务 ( 验收 ) 和任何因修改而造成的错误。它与性能测试、代码覆盖率等一起保证了代码总是在可控范围内,这远比形式化的人工检查要有用得多
可以将测试、版本管理工具、以及自动发布 (nightly build)整合。编写脚本将测试失败结果与代码提交日志相匹配,最终生成报告发往指定邮箱
很多人认为单元测试代码不好写,不知道怎么测试。如果非技术原因,那么需要考虑结构设计是否合理,因为可测试性也是代码质量的一个体现
写单元测试本身就是对即将要实现的算法做复核预演。因为无论什么算法都需要给如条件,返回预期结果。这些加上平时写在 main 里面的临时代码,本就是一个完整的单元测试用例,无非换个地方存放而已
Testing
-
工具链和标准库自带单元测试框架,这让测试工作变得相对容易。关于测试,有以下规则:
-
测试代码须放在当前包以“ _test.go ” 结尾的文件中
-
测试函数以 Test 为名称前缀
-
测试命令 ( go test )忽略以 “ _ ” 或 “ . ” 开头的测试文件
-
正常编译操作 ( go build/install )会忽略测试文件
-
-
标准库 testing 提供了专用类型 T 来控制测试结果和行为
-
使用 Parallel 可有效利用多核并行优势,缩短测试时间
对于测试是否应该和目标放在同一目录,一直有不同的看法。某些人认为应该另建一个专门的包用来存放单元测试,且只测试目标公开接口。好处是,当目标内部发生变化时,无须同步维护测试代码。每个人对于测试都有不同的理解,就像覆盖率是否要做到 90% 以上,也是见仁见智
Table driven
-
单元测试代码一样要写的简介优雅,要做到这一点并不容易。好在多数时候,我们可以用一种类似数据表的模式来批量输入条件并依次比对结果
-
这种方式将测试数据和测试逻辑分离,更便于维护。另外,使用 Error 是为了让整个表全部完成测试,以便知道具体是哪组条件出了问题。
Test main
-
某些时候,须为测试用例提供初始化和清理操作,但 testing 并没有 setup / teardown 机制。解决办法是自定义一个名为 TestMain 的函数,go test 会改为执行该函数,而不再是具体的测试用例
-
M.Run 会调用具体的测试用例,但麻烦的是不能为每一个测试文件写一个 TestMain
-
要实现用例组合套件 ( suite ),需借助 MainStart 自行构建 M 对象。通过与命令行参数相配合,即可实现不同测试组合
Example
-
例代码最大的用途不是测试,而是导入到 GoDoc 等工具生成的帮助文档中。它通过比对输出 ( stdout )结果和内部 output 注释是否一致来判断是否成功
-
如果没有 output 注释,函数就不会被执行。另外,不能使用内置函数 print/println 因为它们输出到 stderr
2. 性能测试
-
性能测试函数以 Benchmark 为名称前缀,同样保存在 “ *_test.go ” 文件里
-
测试工具默认不会执行性能测试,须使用 bench 参数。它通过逐步调整 B.N 值反复执行测试函数,知道获得准确的测量结果
-
如果仅希望进行性能测试,可以用 run = NONE 忽略所有单元测试用例
-
某些耗时的目标,默认循环次数过少,取平均值不足以准确计量性能。可使用 benchtime 设定最小测试时间来增加循环次数,以便返回更准确的结果
Timer
-
如果在测试函数中要执行一些额外操作,那么应该临时阻止计时器工作
Memory
-
性能测试关心的不仅仅是执行时间,还包括在堆上的内存分配,因为内存分配和垃圾回收的相关操作也应该计入消耗成本
-
也可以将测试函数设置为总是输出内存分配信息,无论使用 benchmem 参数与否
3. 代码覆盖率
-
如果说单元测试和性能测试关注代码质量,那么代码覆盖率 ( code coverage)就是度量测试自身完整和有效性的一种手段
-
通过覆盖率值,我们可以分析出测试代码的编写质量。检测它是否提供了足够的测试条例,是否执行了足够的函数、语句、分支、和代码行等,依次来量化测试本身,让白盒测试真正起到应有的质量保障作用。
-
当然,这并不是说要追求形式上的数字百分比。关键还是为改进测试提供一个可发现缺陷的机会,毕竟只有测试本身的质量得到保障,才能让它免于成为形式主义摆设
-
代码覆盖率也常用来发现死代码 ( dead code )
-
为获取更详细的信息,可指定 covermode 和 coverprofile 参数
-
set :是否执行
-
count: 执行次数
-
atomic:执行次数 (支持并发模式)
-
还可以在浏览器中查看包括具体的执行次数等信息
-
4. 性能监控
-
引发性能问题的原因无外乎执行时间过长,内存占用过多,以及意外阻塞。通过捕获或监控相关执行状态数据,就可定位引发问题的原因,从而有针对性改进算法
-
本文来自博客园,作者:slowlydance2me,转载请注明原文链接:https://www.cnblogs.com/slowlydance2me/p/17198528.html