怪怪 | Nothing, Everything

"有过一个发疯的时刻,有感觉的钢琴以为它是世界上仅有的一架钢琴,宇宙的全部和谐都发生在它身上." - 狄德罗
随笔 - 115, 文章 - 3, 评论 - 2114, 引用 - 61
数据加载中……

讨论:老调重弹,测试和可获得的正确性的概率

首先说明,我对测试的了解属于从外部逐渐了解的那种,可以说基本上是外行。但是如果愿意讨论这个问题,希望不要因为我的业余,就完全否认我的说法。另外需要重申的是,我并不否定TDD,因为我认为测试更多的应该发挥一个工程上的作用,我质疑的是通过测试保证正确性。

迪斯特拉说过,测试只能证明一个事情是错的,但永远不能证明一个事情是对的。

这是一句没法否认的话。但是我心里也明白,没有必要要求形式上的、100%可以保证的正确性,关键在于代价和效果的比。如果在“正确性”上,可以得到一个比如99%的概率(请注意哪怕1%的概率,也意味着存在完全正确的可能性,只是心里比较没谱罢了),而使用某种方法的成本很低,这样的做法我完全认同。

问题在於,在复杂度足够高的某些过程上,要达到相同的概率,测试付出的代价超出了构造该过程本身甚至再加上多次、多人验证的代价,而且可能对“是否正确”这一结论引入新的不确定性。在保证正确性这一问题上,连InfoQ这种站的某些作者都指出,比如“净室开发”也可以取得至少一样好甚至更好的结果。

根据McConnell书中引用的报告,相比其它检验手段,测试的BUG检出率即便不是最少那也是相当的少了。你可以认为这是测试做得不到位,但这也揭示了测试作为一种手法,保证正确性这一部分功效,在相当多的工程中也是不可行的:因为我们只能以平均水准要求参与工程的人员。

在这方面,我觉得讨论更先进的测试手法来体现测试的优越性,太过具体,而且实际上最终指向的还是:在给定的条件下,可以保证的正确性概率是否满足要求(如果同一过程在条件之外给出完全错误的结果其实也不是不能接受的);其次,满足要求要花费的成本是多少。在这方面,我也恳请懂行的人可以给出各方面的资料,让我和其它有兴趣深入的人可以更好的了解和研讨。

对于一些过程而言,使用测试在正确性保障方面,因为在覆盖等方面本身存在着可行但成本很高或完全不可行的情况,想要达成某一较高的概率甚至是根本无法实现的(比如迪斯特拉举的例子);而这些过程很可能存在其它的检验手段可以达成目标。理解了这一点(这是进行简单的思维试验就可以弄清楚的),就知道了我这个外行在说什么。

最后强调的是,我不否认测试在工程上所起的作用;甚至在正确性这方面,在很多地方使用测试的可行性也非常高,而相应的成本会比较低。比如Knuth虽然也很不客气的否认测试作为一种手法的优越性,不过在他的具体项目中,也不是完全不使用测试的。但如果只是一味倡导,而完全忽略其中我们需要细心的思考的、可能存在的破绽,我觉得就比较不能接受了。

在本篇中,以过程作为讨论对象,是因为过程的正确是构成软件正确性最根本的基石,尤其是关键性过程的正确,我个人目前不赞成使用测试来保障(虽然还是应该根据过程的特点来决定)。另外需要注意的一点,本文讨论的是正确的概率,而不是测试的覆盖率(虽然这是影响概率的主要因素之一)。

最终,这是一个减小出错风险的效果的性价比问题,在某些过程上,是可行性的问题。另外,我觉得这个问题是一个典型的例子:我们无需深入课题内部各个细节,就可以通过分析思考学到很多的东西,甚至作出有益的判断和决定。

posted on 2008-09-29 18:20 怪怪 阅读(5858) 评论(15)  编辑 收藏 网摘

评论

#1楼    回复  引用  查看    

顶楼主!!单元测试对于TDD是有用的,但是对于debug代价高收效小。
我认为单元测试的目的应该是保证各单元没有偏离需求,而不是很多人(尤其是很多脱离实践的领导)所说的保证软件质量。
2008-09-29 19:30 | YYX      

#2楼    回复  引用  查看    

没有出去玩呀。
2008-09-29 20:24 | 金色海洋(jyk)      

#3楼    回复  引用  查看    

我也写了一个,来捧场呀。
2008-09-29 20:25 | 金色海洋(jyk)      

#4楼    回复  引用  查看    

对于 Developer 来说,至少单元测试这种白盒测试还是必要的。同时这也是检测自己代码正确的有效措施。
2008-09-29 20:46 | Angel Lucifer      

#5楼    回复  引用    

目前呆的团队都是没有测试这一步的,希望以后能会用到。
2008-09-29 23:28 | luchaoshuai [未注册用户]

#6楼    回复  引用  查看    

单元测试对设计,减少BUG,保证质量都是很有效的.
有很多人说它的代价很高,真的是这样的吗!它需要的工作量并不大,只是在于你的设计好坏,在好的设计的前提下,做单元测试需要的时间,也许比你作完程序后,验证BUG的时间还要少
2008-09-30 09:50 | Kevin-moon      

#7楼    回复  引用  查看    

--引用--------------------------------------------------
Angel Lucifer: 对于 Developer 来说,至少单元测试这种白盒测试还是必要的。同时这也是检测自己代码正确的有效措施。
--------------------------------------------------------
同意,在开发人员这一层,UT还是很有帮助的
2008-09-30 12:24 | Anders Cui      

#8楼    回复  引用    

@Kevin-moon
没见过代价高的情况,并不能说明设计好,只能没见过本质上真正复杂的程序,如果否认这种情况存在,说实话我觉得属于根本没好好想过这个问题,只为自己的倾向性表达某种意见。

比如我说的迪斯特拉的说法、Knuth的想法,并非因为他俩年纪太老,事实上这种争论从一开始就存在,肯定的人有没有顺着否定的思路想过?这对肯定的人学习自己肯定的东西也是极其重要的一步。

如果直接下结论,你的说法也完全没有依据,毕竟McConnel引用的报告比你我客观、权威的多。

我觉得掌握测试的人,应该可以举出这样的例子来反映测试保证正确性方面的进步:一个足够复杂的、如果用手写测试,保证某一正确性就基本不可能的过程,然后说明现代工具如何支持这种过程的测试,把代价控制在什么样的范围内,同时避免各种可能存在的问题。

实际上这个争论我倒是觉得必要性不大,关键是不同的样本和目标与不同的手法,如何配对的问题。

#9楼    回复  引用    

这是我最近看到 Cnblogs 首页上唯一一篇值得看的. 整个首页都被原先只能在新手区发布的文章充斥; 甚至转载文章也可以堂而皇之地出现, 对此稍有不满便被拥蹩指斥.

其实我几乎从不用测试的 :)

#10楼 [楼主]   回复  引用  查看    

@未登录的随风流月
呃...,将来你要是发现测试还是有用的(这同样也是事实),可不要怪我 :P
2008-10-03 00:44 | 怪怪      

#11楼    回复  引用  查看    

毫无疑问,测试是必须的,否则必然付出惨痛的代价。但是测试不仅仅是个单元测试,单元测试只是程序员自己做的一种测试,测试还有很多。
测试的目的就在于尽早的发现问题,因为问题发现的越早,解决的代价就越小。

为了省测试的成本,最终的结果可能是在解决bug上多付出了几倍的成本。

我们想想奥运售票网站当时为什么会崩溃,最终都导致了订票流程的改变?很明显,在上线之前没有做过负载测试,最终的代价是惨痛的,整个项目等于废掉了,而且直接影响了客户方正常业务(卖票)的进行。

测试是为了保证软件质量的,并不是说用来保证100%的正确的,测试是为了尽早的发现问题解决问题,而不是累积到最后。
2008-10-03 22:58 | ocean      

#12楼 [楼主]   回复  引用  查看    

@ocean
虽然我自认是测试Hater,但不要搞得我好像要把测试连根拔起似的 :P

不过,“测试是必须的,否则必然付出惨痛的代价”,绝对不是毫无疑问的;如果说这句话有一定正确性,可以说很大程度上是因为这只工程队伍中至少有一些程序员,根本不知道自己在干什么。于是把那些本来可以很简单的证明(可以比测试在更大限度上作出保证),变成了非得花很大代价尝试个遍(往往还不可能)心里才靠谱的事情。

当然,这种现象的产生,并不能归咎为程序员素质普遍偏低;很显然,越来越多的程序员需要知道越来越少的事情,这是生产力提高的必然道路。

我个人认为症结仅仅在于(除了意图穷举各种可能性的测试之外)当前用来保证正确性的工具和手段还远远不够;但我们不能因为暂时没有更好的办法(或者仅仅是没能掌握),就过高估计在很多情况下实际上是二流的方式。

总之,计算机的行为本身总是确定的可估算的,而算法本身是可以证明的,笔误又是可以被检查的;那些由边界外的环境产生的相关不确定性,光靠测试也是不能保障的。仅仅是估算、证明、检查等等以及创造它们的自动化工具,这些事情的难易度和成本问题,使得测试变得在很多情况下是更好的方案;但即使是这样,我们也要注意,在另一些情况下,测试就未必那么靠谱和合算。

我觉得虽然大多数程序员不会接触计算机核心科学领域,但一些最核心最基本的概念,愿意去接触总会有些好处,不愿意花这个功夫的也自有现实的道理。争论其实意义不大,关键还是落实要点,进行合理的选择。
2008-10-07 04:08 | 怪怪      

#13楼    回复  引用  查看    

可能把不少概念混到一起了,没有理清楚

测试是test,"可获得的正确性"是质量保证QA方面,test不等于QA
虽然目标一致,但test侧重于按照需求设计用例场景,确保这些用例能够pass,它的目的就达到;QA则涉及到过程管理学,内容广泛,例如流程完善管理、过程的跟踪确认、风险管理、项目的成本绩效、历史数据的统计分析寻找持续改进方案等等
所以test只是QA的手段之一,没必要刻意追求test对QA有30%还是70%的作用; 讨论正确性应该关注QA,讨论test应该关注方法、技术、工具

程序的正确性都是有条件的,离开这些条件就不存在所谓的正确性,很多时候这些条件的主观因素大于客观因素;
"测试只能证明一个事情是错的,但永远不能证明一个事情是对的"没有表达什么有意义的东西,就如"可能发生的事情它一定会发生","可能"表明概率的存在,概率则代表"一定会"的成立,这样的结论无法给test, QA带来什么影响

从主观方面看,坠机事件是存在的,但我不会太多考虑这方面来选择是否乘飞机;买车的时候,一款做过碰撞测试,一款没有做过,知情的情况下一定会仔细考虑的

理论、科学、工程上,测试都是非常有效的手段
"计算机的行为本身总是确定的可估算的": 排除掉类似晶体管制造问题、芯片设计制造缺陷等情况,还存在操作系统、各种运行平台、底层的第三方的框架类库、各种用户设置等,我对自己写的东西没法相信这句话是成立的
"算法本身是可以证明的": 算法可以被证明,但无法证明一个程序实现方案无缺陷的实现了这个算法
"笔误又是可以被检查的": 不符合文法的笔误是可以被检查出来,符合文法的笔误呢?例如一个函数指针,一字之差写成了另外一个

总之通过测试找出编码上常见、主要的缺陷,用比较小的成本解决这些缺陷,这是公认的,这个隐含的观点就是测试是很有效的
对于那些极少数,并非普通的情况,没有必要来否认这一点。值得思考的,是特定的环境下怎样制定、实施QA措施,怎样让测试变得更轻量级(低成本)更有效
2008-10-07 15:05 | RicCC      

#14楼    回复  引用    

@RicCC
基本上咋俩还算是比较靠中间的,不过就这个问题,还是有偏左、偏右。

(以下说法近局限于正确性方面)

关于测试的有效性,请注意我提到的McConnell引用的报告,和其它相关的,比如代码审查和测试之间的比较。 这并非是我空口说白话。

其次,软件方面,“晶体管制造问题、芯片设计制造缺陷”,测试也不能保证任何事;而“操作系统、各种运行平台、底层的第三方的框架类库、各种用户设置”,属于knuth说的,不知道会产生什么效果的情况下,应该测试。

在这种观点下,测试应该是针对这些我们不了解、也无法控制的点。

“一个程序实现方案无缺陷的实现了这个算法”,那么我们可以认为这个问题是翻译过程中出现了失误, 简单地说我们不能杜绝这个失误,我觉得未免太不乐观;实际上,某种语言仅仅是一个表达方式,就是以这个语言写下这个算法,这既是实现,又是可以证明的算法本身。如果单纯的认为是人就会写错,那么别说小小的软件界,那么历史上每个证明所进行的表达,以及整个科学大厦都可以轰然倒塌了。

“不符合文法的笔误是可以被检查出来,符合文法的笔误呢?”,这仅仅是工具不好用,现在虽然搞不靠谱的动态语言的人很多,但是搞静态检查的人也不少。符合文法,但意义不对的笔误,不能被自动检查,仅仅是因为概念本身没有在文法中表达并在构造系统时得以表现。 包括当前大多数的静态语言,从C到Java。

换个不那么贴切的例子: 比如SQL,Select T.Column1 from Table1 T, Table1、Column1,这在给定数据库上都是可以检查的不是?所以关键还是实现检查工具的成本问题,而我比较乐观,这些问题必然最终会得到解决。

“"测试只能证明一个事情是错的,但永远不能证明一个事情是对的"没有表达什么有意义的东西”

这个就只能是仁者见仁,智者见智了。也可以说是角色不同,认同度就不一样。在这个问题上,就不用拿别人来举例子了,如果一件事明明存在一个更有保障、且代价更小的方法,我却采取另一个,那么只有一个原因: 在前者的领域里我太菜,以至于不能掌握那些方法,仅此而已。

这个讨论的起始点是《代码之美》中某测试牛人以2分查找讲测试的那一章。说实话,我看这章时只有一个感觉,就是可笑。在这个问题上,我不打算当和事佬, 对的就是对的,错的就是错的。

实际上,很多代码的正确性,甚至可以做到一个程序员写完的那一刻,它就是对的(当然要辅以合适的工具);除非这个程序员根本没闹清楚他要的是什么。在后者的情况下,即便有测试,也不能保证任何事情,这也是我从McConnell引用的报告中看到的事实。

当然,现在在大多数领域,所谓“合适的工具”还没有出现,我也仅仅是指出一个可能的、努力的方向。另外, 在当前的条件下,如何恰到好处的应用测试也是我所关心的, 可却没有人回答这个问题。

比如回到2分查找的测试,有谁能提供书里那测试牛人所保障的东西, 同时其代价不要像他做出的努力那样, 大大超越2分查找这个算法本身的实现代价?实际上测试的必要性,往往是和语言休戚相关的;比如动态语言就需要更多的测试。

如果语言和语言周边工具可以再上一层楼,任何一个普通的程序员都可以像Knuth一样,自信的说出I didn't try it, I only prove it correct。就好比你我永远不会给i++做一个测试一样。

最后说一句,你澄清的概念又让我学到不少东西,谢谢啦 :)

#15楼    回复  引用    

"概念本身没有在文法中表达",应为“文法没有给概念一个合适的表达方式”

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-09-29 20:10 编辑过
Google站内搜索

China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》



相关文章:

相关链接: