单元测试是保证代码质量的重要一环,在实际生产中是需要特别加以重视的。Go语言自带了简单易用的单元测试框架,不仅支持功能测试而且支持性能测试,使用自带的命令行工具可以进行强大的测试分析。
为了演示方便,我们先创建一段简单的待测试代码:
基础单元测试
go的单元测试文件需要以结尾,比如对于上面的caculator包下的caculator.go文件,我们可以在caculator包下建立作为单元测试文件。
单元测试文件中可以自动识别三类测试方法:、、,以下分别介绍:
Test
以开头的方法,是对所要测试方法的功能测试。
如上面代码所示,Test测试方法需要接受类型对象作为参数,该对象提供了丰富的测试需要的功能,例如方法就可以告诉程序测试出现了错误,并将错误信息打印。
执行单元测试也很简单,使用命令即可:
默认情况下,如果所有的测试都通过,则只会输出一行结果,如果想看到执行测试的过程以及我们通过输出的内容,可以加参数:
请注意:最后一行结果中表明本次测试结果来自缓存,这是go为了提高测试效率所做的一种优化,如果想禁用cache,通常有两种方式:
进入想要测试的包,在包下执行,不加package参数的指令将不使用cache:
第二种方法就是使用参数:
还支持我们在一个测试方法中执行多个测试用例:
执行结果如下:
Benchmark
以开头的方法是性能测试方法,go在语言层面直接支持了性能测试,并提供了灵活的命令行工具,还是很强大的。
如上面代码,我们循环执行次Add方法,是一个系统会自动调整的变量,会根据方法的执行时间自动设置一个合适的值。
执行结果如下:
默认是不执行Benchmark开头的性能测试的,如果想要执行,需要加参数,并指定匹配的方法,即指所有方法。指定需要执行2次。注意结果中的,结尾的这个4代表当前最多可以使用4个cpu来执行(本人电脑是4核的)。
上面的Benchmark测试是串行的,我们还可以使用并行的方式:
运行结果如下:
指定测试时会尝试使用1个cpu和2个cpu分别测试,当使用多个cpu时,将分配次到这些cpu上,不指定参数时,将默认使用(即能够使用的最大cpu数)。
通过以上的实验,我们发现对于这种功能简单的方法,使用串行测试的平均耗时是0.31/ns,使用并发测试时,cpu数量越多,平均耗时越少,根据方法的说明,它会将次测试任务通过goroutine的方式分配到可用的cpu上,至于为什么是这个结果,本人暂时没有考虑明白,留待后续分析。
Example
以开头的方法是示例方法,如果出现在_test结尾的测试文件中,也将被执行(准确的说,是当Example方法中包含注释的时候)。
我们先来解释一下什么是Example方法:Example方法通常是出现在文档中的示例,方便文档阅读者知道某个方法该如何使用。只要我们在_test结尾的测试文件中编写以Example开头的方法,在我们使用生成的文档中,将会在对应方法的说明中出现示例。例如:
我们先使用将caculator包安装到目录下,然后使用就可以启动一个http文档服务,打开将可以看到文档内容:
在菜单拦中点击“Packages”,将可以找到我们install进去的caculator这个package,点击进去,可以看到如下结果:
Example已经安静的在那里等你了,惊不惊喜?意不意外?
上面的测试将比较方法的输出是否是3,如果不是将会报错。执行结果如下:
方法本身会输出4,而我们期望结果是3,结果报错了,我们把期望结果修改为4后,再次执行:
对Example进行单元测试,是为了防止出现Example方法由于过时导致的错误,如果每次代码更新都能及时进行测试的话将可以有效避免这个问题,看来Go的设计者真是用心良苦。
Mock
对于工具类,我们通常可以直接使用go自带的testing包进行单元测试,但是对于那些有很多依赖,尤其是依赖IO,网络等的方法,测试起来就没有这么容易了,逻辑彼此依赖,我们关心的代码逻辑常常因为网络环境,或者其他上下文依赖不ok而导致错误,因此Mock测试框架应运而生。
为了便于说明,我们依然举一个例子:ofo单车上有密码锁,密码锁最开始是转盘形式,后来是按键形式的。按照面向接口编程的思想,我们需要抽象出一个接口:
我们定义按键锁:
我们再来定义单车:
接下来,我们就需要对OpenBike方法进行测试了,显然,OpenBike方法依赖Lock,由于我们只是想测试单车是否能开锁,并不想具体测试锁本身是否好用,因此就需要对Lock进行mock。
go有多个框架可以提供mock测试,常见的比如,等。本次我们来尝试使用gomock。gomock是典型的面向接口进行测试的框架。具体的安装我们不再赘述,可以参考官方文档,这里直接给出测试代码:
测试覆盖率
测试覆盖率是反映我们测试代码覆盖分支多少的指标。在生产环境中通常都会有一定的要求,达不到的话不允许部署上线。
强大的go自然也为我们提供了分析测试覆盖率的工具:
说明bike包中代码覆盖率达到100%,nice!
除此之外,我们还可以将测试覆盖率生成一个测试报告:
之后,我们就可以利用工具来进行分析:
从中我们可以看出哪些文件覆盖率较高,哪些文件覆盖率较低。
还可以获得html的分析结果:
该命令将打开一个html网页,展示已覆盖和未覆盖的语句,如下图所示:
参考资料
Go单元测试
go command#Test packages
Go 语言测试(Test)、性能测试(Benchmark) 学习笔记
The cover story
golang/mock
领取专属 10元无门槛券
私享最新 技术干货