有一种说法:程序员测自己的代码效果不好,因为测试是找错,程序员不愿意去证明自己是错的,别人测效果才好,对吗?这种说法是根本错误的,误导了无数人。正好相反,单元测试要自己测效果才好,别人测则几乎没有效果,除非有函数级的详细文档。
单元测试的三种方式:程序员编码同时测试、程序员编码后测试、由别人测试,成本的比例大概为1:3:5,测试效果的比例大概为5:3:1。这是指一般的开发过程,其特征是没有函数级的详细文档。
我们先来看看大家耳熟能详的几个概念:需求、设计、实现。需求是“要做什么”,设计是“具体怎么做”,实现是“做出来”。写一个函数,不管写不写文档,需求、设计、实现仍然是必经的过程,只不过面对的目标很小而已。
写一个函数,程序员要想清楚“要做什么”和“具体怎么做”,这是所想。显然,所想的就是需求和设计。把代码写出来则是实现,这是所做。
如果在写代码同时测试,测试用例一定是依据“所想”而设计的,测试的结果是验证“所做”是否符合“所想”,也就是说,测试的结果是:验证实现是否符合需求。这种方式,需求是清晰的(虽然只是在程序员的脑子里),所以效果最好,而用例只需根据“所想”直接设计就行,还可以利用测试来驱动开发,所以成本最低。
程序员编码后测试,“所想”已经忘了一部分,要根据代码来“恢复”,但是不可能全部“恢复”。测试的结果,有可能是“验证实现是否符合需求”,也有可能不是,所以效果会打折扣,由于要花时间来“恢复”所想,且不能利用测试来驱动开发,所以成本也会高得多。
由别人测试,用例设计的依据是什么?除非程序员在编码时把“所想”记录下来,形成函数级的详细文档,否则,“别人”只能读代码来确定需求,实际上,这个“需求”是实现本身,测试的结果是:验证实现是否符合实现,俗称“跟着代码走”,这样的测试有什么意义?成本方面,需要读代码来确定需求,无疑很费时间,所以成本最高。
举个简单的例子来说明。程序员要一个加法函数,结果写成了:
int fun(inta, int b) { return a - b; };
编码时测试,程序员一定知道自己要写的是加法函数,用例为a=1; b=2;ret==3,当然能发现错误。
编码后测试,程序员有可能想起这是加法函数,测试能发现错误,也有可能忘了,读代码后认为这是一个减法函数,这样测试就没意义了。
别人测试,只能读代码,认为是减法函数,测试没意义。
当然,实际的情形不会那么单纯,代码可能有一些注释,“别人”也许能了解代码的大致需求,所以“别人”测试也会有一些效果,但是,单元测试主要做的,是找出实现与需求之间的细微偏差,例如,一些输入下代码是正确的,一些输入下,代码有问题(未分类处理这些输入或处理错误),“别人”即使能够了解代码的大致需求,也难于了解全部需求,测试效果总是很有限的。
也许有人会说,边编码边测试,虽然依据的是代码的需求(小需求),但是这个需求是否符合系统的整体需求(大需求)呢?换几句话说,本来这个函数要做的是A功能,但程序员所想的是B功能,那测试不是没有意义吗?一、由别人测试,跟着代码走,这个问题同样存在;二、这种错误在集成后很容易发现;三、这种错误很少。用小需求不一定符合大需求来否定程序员测试自己的代码,那就是因噎废食了。
总之,一般情形下,程序员编码同时测试、程序员编码后测试、由别人测试,三种方式的成本的比例大概为1:3:5,测试效果的比例大概为5:3:1。这个比例只是定性,我无法精确证明,信不信由你,反正经过十多年的实践,我是信的。
转载于:https://blog.51cto.com/easytdd/1411954