为何没有单元测试就没有高质量代码?

来源:互联网 发布:国服lol mac版 编辑:程序博客网 时间:2024/03/29 22:23

写代码的几乎都不写单元测试,写单元测试的几乎都是被逼无奈。

只有当自己的目标是写自己的软件,质量当然是最重要,而且没有时间限制时,才会认真写单元测试。

当然如果工作也能达到这个状态,也能获得高质量代码。

几乎没有谁一下子就能设计出完美的接口和写恰当的注释,有些知名的开源软件也没有单元测试,但是人家有总多参与者,其实CR读代码的过程也是一个单元测试的过程。

据我来看,单元测试有以下的重要作用。

单元测试找到最小接口

什么是最小接口?一个类有2个函数,和1个函数,对于使用者/维护者/新人/其他人/以后的自己,都有很大的区别,如果1个函数能搞定,就只需要理解一个函数。

往往项目增长时类也在增长,SRS在4万行代码中有338个类,如果每个类多一个函数,就多出338个函数需要理解。

因此,最小接口是代码改善的重要目标,直接影响代码的理解复杂度。

参考一次utest时对于类接口的删减:https://github.com/winlinvip/simple-rtmp-server/commit/8992e217a947ccddbcdc5aea7ecee6d1db966cb7#diff-89f12adbfc348747cba9217a462b968cR50

如下图所示:


原来是size/empty/bytes/erase/clear五个接口,删减为length/bytes/erase三个接口。

为何有效的单元测试会精简接口,找到最小接口?其实是因为单元测试最烦躁测试重复的函数嘛,测试的函数越少越好。

单元测试明确函数的职责

有的时候,特别是某些内存分配的函数,譬如收发消息,内存是在函数内部分配,还是在外部分配?着急的时候就不太会写得很清楚。

有些地方,譬如flv是读取了头,还是读取了头加4字节的previous tag size,这个在写函数时不太可能详细说明和仔细的考虑名字。大多就是read_header就可以了。

这些信息其实不是那么有问题,读读代码也知道,但是对于精确的函数职责(函数名和注释),是高质量代码的基本要求。

举个实际的例子:https://github.com/winlinvip/simple-rtmp-server/commit/d219a7b67ea615e2e57accfb5f934d2b50037834#diff-7cb021c27d705d37d4f547c504f7d0fbR136

如下图所示:


除了注释说明了头的大小,还将函数名改成了read_header_ext,作为区分。

为何在单元测试中才发现这些细节?因为当时写的时候是很明确知道这个函数的意义。等过了一段时间,就得看看代码才知道(注释写得不够明确)。

让bug不再重复出现

有时候某段代码fix了一个bug,有的加了注释,有的没有加注释。

在新版本开发时,新加入的开发人员看不懂这段代码,当然会觉得这种代码是“无意义的死代码”,会改动或删除这段代码,导致bug重新出现。

而对于重写的软件更加明显,除非把bug都过一遍,否则之前的bug大部分时候还是会重出江湖。

utest是对于这种情况的最好保障,前提是别老重写,或者重写时把utest也得重写了。

以一个bug为例,注释说得很清楚:



用utest来保证:


可惜这种utest写起来相当之需要精力,可不是么,难道高质量的软件就那么容易写出来?

0 0
原创粉丝点击