关于code:Golang代码测试一点到面用测试驱动开发

9次阅读

共计 2734 个字符,预计需要花费 7 分钟才能阅读完成。

​​​​摘要:TDD(Test Driven Development), 测试驱动开发。冀望部分最优到全局最优,这个是一种十分不错的好习惯。

理解 Golang 的测试之前,咱们先理解一下 go 语言自带的测试工具。

go test 工具

Go 语言中的测试依赖 go test 命令。编写测试代码和编写一般的 Go 代码过程是相似的,并不需要学习新的语法、规定或工具。

go test 命令是一个依照肯定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go 为后缀名的源代码文件都是 go test 测试的一部分,不会被 go build 编译到最终的可执行文件中。

在 *_test.go 文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数。

运行流程

go test 命令会遍历所有的 *_test.go 文件中合乎上述命名规定的函数,而后生成一个长期的 main 包用于调用相应的测试函数,而后构建并运行、报告测试后果,最初清理测试中生成的临时文件。

单元测试

以下是来自 wiki 对于单元测试的定义

在计算机编程中,单元测试 (英语:Unit Testing)又称为 模块测试,是针对程序模块(软件设计的最小单位)来进行正确性测验的测试工作。程序单元是利用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是办法,包含基类(超类)、抽象类、或者派生类(子类)中的办法。

通常来说,程序员每批改一次程序就会进行起码一次单元测试,在编写程序的过程中前后很可能要进行屡次单元测试,以证实程序达到软件规格书要求的工作指标,没有程序谬误;尽管单元测试不是必须的,但也不坏,这牵涉到项目管理的政策决定。

每个现实的测试案例独立于其它案例;为测试时隔离模块,常常应用 stubs、mock[1]或 fake 等测试马甲程序。单元测试通常由软件开发人员编写,用于确保他们所写的代码合乎软件需要和遵循开发指标。它的施行形式能够是十分手动的(透过纸笔),或者是做成构建自动化的一部分。

简略来说,单元测试就是程序员本人对于本人的代码进行测试,而一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是办法,包含基类(超类)、抽象类、或者派生类(子类)中的办法。

更有一种开发手法,那就是 TDD(Test Driven Development), 测试驱动开发。冀望部分最优到全局最优,这个是一种十分不错的好习惯。

请留神这里的部分最优的,部分,并不是函数内的具体。而是整个函数。甚至是一个类,等等。

因为有些函数外部的最优,并非这个函数的最优。这点咱们须要分外的留神。若有趣味,可理解一下有点关系的贪婪算法。

测试函数格局

其中参数 t 用于报告测试失败和附加的日志信息。

testing.T 的领有的办法如下:

说了这么多,那么咱们来实现一个简略的 string 中的 Split 函数,并对他进行单元测试,而后咱们在分析代码。理解单元测试的相干标准。

运行后果如下

阐明测试胜利,本次通过。当然你也能够在 Terminal 外面间接运行 go test,命令,如下所示

舒适提醒:对于可能造成运行 test 不胜利起因

间接在 split_test.go, 运行。

咱们或者晓得,go 是以文件夹的办法来辨别我的项目。所以以后文件,并不能跑到旁边文件中去找到 Split, 以至于测试失败。或未达到预期成果。

那么正确的打开方式应该是?

在 goland 中,鼠标右键点击 run 测试文件所在的文件夹,抉择前面第二个 go test projectFileName。

在 Terminal 中,应在测试文件所在的文件夹的门路中,进行 go test [arge…]。

示例看完了,那么咱们进行简略的分析。咱们先从函数文件说起,(也就是这里的 splits.go)。

  1. 不在是 package main, 而是 packge projectFileName
  2. 函数名大写,大写意味着私有函数,可反对内部调用

测试文件

  1. 文件名为 ’*_test.go’
  2. 不在是 package main, 而是 packge projectFileName
  3. 函数名为 TestFuncName

基准测试

基准测试函数格局

基准测试就是在肯定的工作负载之下检测程序性能的一种办法。基准测试的根本格局如下:

基准测试以 Benchmark 为前缀,须要一个 *testing.B 类型的参数 b,基准测试必须要执行 b.N 次,这样的测试才有对照性,b.N 的值是零碎依据理论状况去调整的,从而保障测试的稳定性。testing.B 领有的办法如下:

基准测试示例

咱们为咱们本人写的 Split 函数编写基准测试如下:

其中 BenchmarkSplit:示意对 Split 函数进行基准测试

BenchmarkSplit-8:数字 8 示意 GOMAXPROCS 的值,这个对于并发基准测试很重要

5188407 和 206ns/op:示意每次调用 Split 函数耗时 203ns

咱们还能够为基准测试增加 -benchmem 参数,来取得内存调配的统计数据。

112 B/op:示意每次操作内存调配了 112 字节

3 allocs/op:则示意每次操作进行了 3 次内存调配!!!

优化后代码如下:

优化后代码如下

这个应用 make 函数提前分配内存的改变,缩小了 2 / 3 的内存调配次数,并且缩小了一半的内存调配。

仅仅小小的一处改变,就引起如此大的性能扭转。so good 质变产生量变

性能比拟函数

下面的基准测试只能失去给定操作的相对耗时,然而在很多性能问题是产生在两个不同操作之间的绝对耗时,比方同一个函数解决 1000 个元素的耗时与解决 1 万甚至 100 万个元素的耗时的差异是多少?再或者对于同一个工作到底应用哪种算法性能最佳?咱们通常须要对两个不同算法的实现应用雷同的输出来进行基准比拟测试。

性能比拟函数通常是一个带有参数的函数,被多个不同的 Benchmark 函数传入不同的值来调用。举个例子如下:

例如咱们编写了一个计算斐波那契数列的函数如下:

咱们编写的性能比拟函数如下:

运行基准测试:

这里须要留神的是,默认状况下,每个基准测试至多运行 1 秒。如果在 Benchmark 函数返回时没有到 1 秒,则 b.N 的值会按 1,2,5,10,20,50,…减少,并且函数再次运行。

最终的 BenchmarkFib40 只运行了两次,每次运行的平均值只有不到一秒。像这种状况下咱们应该能够应用 -benchtime 标记减少最小基准工夫,以产生更精确的后果。例如:

这一次 BenchmarkFib40 函数运行了 50 次,后果就会更精确一些了。

使用性能比拟函数做测试的时候一个容易犯的谬误就是把 b.N 作为输出的大小,例如以下两个例子都是谬误的示范:

本文分享自华为云社区《Golang 代码测试(code review)》,原文作者:PayneWu。

点击关注,第一工夫理解华为云陈腐技术~

正文完
 0