默哀说一句话

2008年04月29日 10:43

胶济铁路火车相撞70人死亡416人受伤

幸运的姜大宝

老詹

当我们面对数字已经麻木,是时候关心一下出现在事件中的具体的

单元测试

2008年04月28日 13:36

周五跟猛禽聊了几句关于单元测试的问题。正好最近参与的一个项目里我也把单元测试放到很重要的位置并且也发现了一些问题。顺便整理一下。

这不是一篇严谨的技术文章。只是一些个人不成熟的感想。

在实际开发过程中,我发现在单元测试代码中经常会出现两种情况:第一种就是在测试代码中炫耀编程技巧,第二种就是敷衍了事,你不是让我通过测试么?好,我就写一个用例,一定能通过的那种,然后告诉你,OK,我的测试通过了。我觉得,这就是对单元测试的意义没有真正理解的表现。

到底单元测试是做什么用的?我想,在说明这个问题之前,我先说说我所理解的测试到底是做什么用的。

所谓的测试,是一种产品质量保证的手段。我按照需求规格说明书制造了一件产品,那么谁来确保这个产品符合了需求规格的要求呢?就是测试。它会根据需求规格说明书设计一系列的场景和用例,来对产品进行测试,看看产品是不是真的符合所期望的需求。

要达到这个目标,其实并不十分的容易,因为一个真正的系统,情况十分复杂,里面充满了数不清的分支、异常、边界条件,甚至运行环境,将这些东西组合起来,产生的需要测试的点将会是一个天文数字,在有限的时间内做完一个充分而可靠的测试,是不可能的。

为了将充分测试变得可能,一个比较好的途径就是分层测试。我在做运行测试或性能测试的时候,有一个前提,就是假设整个系统的集成运行已经没有问题了,在运行测试或性能测试时,我将不再考虑“系统无法正常运行”这种场景。那么如何保证集成运行没问题呢?我们用集成测试来检验。但是在做集成测试的时候,我们同样要基于一个假定,就是各个模块的功能都能够如期正常工作。而这一点,又是通过模块自身的功能测试来完成的。……这样一层层往下推,每个层次就假设它所依赖的层次没有问题,这样就可以减少很多场景以及由这些场景引出的额外的分支。将原先一个几何级数的测试用例分解成可以接受的若干层次的算术级数的用例。这样一来测试就变得有可能做好了。

而单元测试,正是这些测试的最低层次——保证每个函数/方法,或者说最小功能模块的正确性的一种测试。

通过上面的描述,我们至少清楚了这样几件事情:1. 单元测试是一种测试,它不是代码的一部分;2. 单元测试是最低层级的测试,它只保证函数的可靠性,不保证其它;3. 单元测试应该能保证每一个函数的可靠性。

单元测试是一种测试,所以,我们应该以一种测试的眼光去面对它——我们要测试正常情况,边界条件,要对它的测试目标——函数做黑盒分析,白盒分析,选择合适的测试数据,构建测试场景和测试环境——总之,一切测试应该做的事情,单元测试都不应该省略。

理论上来说,单元测试和其他测试一样,也是可以纯手工完成的:我们可以写一段某函数的测试代码,然后输入我们的测试输入,观察测试输出,并跟期望值做比较——事实上这种人工测试,写了一段时间代码的人应该都不会陌生。但是,单元测试有一点特殊性,就是在一个系统中,函数会非常非常的多,变化也比软件的功能频繁的多。面对这么多的函数,这么频繁的变化,纯手工测试是不现实的。所以,我们必须要引入单元测试框架进行自动化测试。注意,这里的单元测试框架只是实现自动化测试的一个手段,对单元测试本身并不产生任何影响——没有单元测试框架,单元测试一样也是可以进行的,只是会痛苦很多。

单元测试框架引入的目的只是为了自动化单元测试,简化单元测试的步骤。所以,对于测试代码的编写,我们的重点应该是:1、如何搭建测试环境、测试场景;2、如何选择测试用例;3、如何校验测试结果。对于测试代码本身,应该尽可能的简单,能不要使用技巧尽量不要使用,我们的目的在于测试,如果测试本身过于复杂,我们不能保证测试的正确性,测试这个工作就白做了。

另外,刚刚提到单元测试是对函数的测试,因此,测试必须是以函数为单位的。每个函数应该拥有自己单独的一个测试,但是在这个测试中,我们应该针对这个函数的各个方面:正常的、异常的、边界的……等等,各个方面进行完善的测试,这样我们才能保证这个函数的功能是如我们所愿的。但是单元测试不需要负责函数的组合工作情况。那应该是(低层次)功能测试的工作,而不是单元测试的工作。这个功能测试就是在假定所有函数都工作正常的基础之上,对这些函数组合形成的功能模块进行测试。这种测试,视情况而定,可以使用单元测试框架,也可以使用其他自动化测试方法或者甚至是使用纯人工测试。

另外,我还想讨论一下单元测试的编写和运行。

绝大部分时候,单元测试的编写,是由开发人员做的。我们在以前某次对单元测试的讨论中,甚至有人认为,单元测试必须由开发人员完成,而不应该由独立的测试人员完成。对于这个问题,我是这样看的:测试是一种针对需求的验证工作。如果这个需求非常清晰,清晰到开发人员之外的人都可以轻易掌握(有些日本外包发出来的函数说明书就能达到这一点),这时单元测试可以由独立的测试人员完成。但是大部分情况下对于函数级别,做不到这一点。这时最清楚函数需求的人就是开发人员本人,在这种情况下当然就应该是开发人员自己编写测试用例。但是开发人员必须搞清楚自己身兼两个不同的角色:运动员(实现代码)和裁判员(检验代码),在编写测试用例的时候绝不能假定任何函数的实现,而应该完全按照它应该有的需求来做。这样才能做好单元测试这件事。很多时候单元测试形同虚设,就是因为开发人员没有很好的转换自己的角色造成的。

单元测试的运行,目前我们这个Python的项目比较容易,直接运行模块就是该模块的单元测试,而以模块形式import就是实际使用。对于像C++或者其他的一些语言来说,可能没有这样方便的形式。我们可以把测试写在独立的文件中,然后用makefile组合不同的项目和主函数来做到这一点。另外还有一点就是,实际运行过程中可能会有一些环境,这些环境在测试时难以获得,或者增加上去之后,就难以测试(比如网络环境、数据库环境等等),这时我们可以采用一些虚拟的环境来做到。我们把运行时需要的环境做一个简化的虚拟版本,然后以这个版本作为测试环境进行测试,对于Python来说,我们可以实现这样的一个库在测试时import进来并且同时做一些环境初始化工作,在C++里,我们可以专门为测试写一些运行库,在实际运行编译和测试编译时,链接不同的库。这在自动化测试技术中有个专门的名称叫做 Mock Object。关于这个,我就不再深入了。

[补记]418群P小记

2008年04月21日 17:01

话说饭否猛禽、京京互相扭捏几日,约在4月18徐家汇群P。

下班后匆匆忙忙赶往群P地点,到目的地后,发现猛禽京京已经在一起了【注:不许联想】。不久,MK、女王陆续赶到。商量FB事宜。

在MK的推荐下,一行人等走啊走啊走啊走啊走了很久,最后来到超没创意的葡京煲煲好坐定。

点完菜没有上的时候,MK突然掏出两大坨东西说是送给京京的礼物。结果原来是二者择一。据说另一枚要送给表妹?京京选好正开心的准备拿走之时,MK大喝一声“慢”,遂从袋中掏出一物,众人定睛细瞧,原来是AA电池两付。再打开礼物,只见一只小毛驴做张牙舞爪状。装上电池,MK温柔地捏了一下小毛驴的手,那小毛驴居然疯狂扭动起来。众人崩溃。

送礼物仪式完毕后正式上菜,只记得有猛禽最爱的豆腐以及让大家很囧的包裹着芥末的炒青菜。席间边吃边聊,倒也收获无限。

京京贡献了女仆装、BL、同人、攻、受等很黄很暴力的词若干。

MK贡献“一个鬼子三百块”经典语录一句。

女王贡献学漫画的表妹一个,故作纯情状一份。

猛禽贡献信用卡一张,照片若干。

令狐虾米也没有贡献。很傻很天真的笑了一晚。

饭毕想群P MBA未遂。在地铁站分手后猛禽和京京独处,后续事宜不得而知。【注:不许联想】

坚决你的立场,宽容你的态度

2008年04月15日 14:30

最近因为西藏以及奥运火炬的事情,网上显得特别热闹。有些人骂有些人汉奸卖国贼,有些人骂有些人愤青低能儿,有些人想一边呆着吧,结果被人骂冷血胆小鬼。总之无论你站在哪个立场,基本上都不会避免被攻击的命运。如此景象实在是很难不让我联想起40年前极其相似的一幕。

最近又有人因为奥运火炬传递在法国的遭遇,呼吁大家抵制家乐福超市。于是乎因为抵制不抵制的问题,又吵得不亦乐乎。

我不知道为什么很多人会有这样一种想法:世界上只存在一种正确答案,除此之外的答案都是错的。并且很多人会不厌其烦的试图去纠正别人“错误”的想法。其实这么做,跟他们所痛恨的洗脑、填鸭式灌输有什么本质的区别呢?

世界上的很多事情都不止只有一种正确答案。我们要坚持自己所认为的那个正确的答案,并找到足够的证据去维护它,不要轻易的被他人左右。另外,我们也应该宽容对待其他的答案,因为他们也有可能是正确的。不是么?

西方媒体错了,不等于中国政府做得对;同样的,中国政府做错了,也不等于西方媒体就正确。有人想抵制这个抵制那个,我觉得没问题,但是并不代表不抵制的人就不爱国不正确。烧杀抢掠是犯罪行为,当然是要反对的,但如果认为对方犯了罪因此自己就可以对他烧杀抢掠,这就不对了。

说到这里我重申一下我的立场:作为中国人我反对藏独,但我可以接受在中国之外的和平示威的行动。我也更加支持中国人无论在国内和国外,以任何形式的和平示威表达自己政治立场的行为。但我反对任何形式的暴力行为,无论是藏独者还是爱国者,也无论是肢体暴力还是言语暴力。

生命未必是用来浪费的,但……它是你自己的

2008年04月10日 14:56

猛禽写了一篇《生命是用来浪费的》,写得深于我心有戚戚焉。不过,我觉得还是有点话要说。

我想说话之前,总得先定义一下什么是浪费,否则在一个意义不明的基础上讨论,总有点鸡同鸭讲的味道。

根据猛禽在文中的描述,我想,这里的浪费应该指的是:花时间在某件事上,却没有实质性的回报。(实质性是指给自己带来名、利或其它普遍意义上的好处)

我曾经碰到过一些人,他们从不做“浪费”的事情。他们所做的每一件事,都是精心计划的——赚钱,投资,赚更多的钱,提升自己的生活品味,交更好的朋友,利用人脉,做更有野心的事……。闲情逸致对他们而言是没有意义的,并不是说他们不活动,他们很会休闲,很会玩,但是他们是当作一种感情投资在做这种事的。

他们有房有车,有钱有闲,但他们并不像我们认为的那样奔波劳累,生活枯燥。事实上他们一样活得很开心。因为这些事情就是他们的追求,就是他们快乐的源泉。

这又有什么不好呢?

诚然,我们无法理解和认同他们的生活,他们同样也不可能理解和认同我们的生活。但是,两种人都有自己存在的理由。我们无需也不该因为自己站在某一边而去BS另外一边的人。

每个人都有自己的想法和活法。关键还是要活着开心。毕竟,生命是你自己的,你有权也有责任把握它。不是么?

裸奔之后

2008年04月10日 13:47

昨天听说是CSS裸奔节。于是就跟风了一把。

结果:

  • 裸奔之后页面还算蛮整齐的。
  • 发现Skip to content功能有bug,修正之。
  • N多人问我的blog怎么了,是不是坏了。

装相反的D的感悟:

  • 我对页面标准还是有点概念的。得益于Firefox为我打开的那一扇窗
  • 有些问题会被华丽的外表所掩盖,只有剥去层层包装,问题才能得以显现。
  • 虽然从本质上而言,核心内容才是最重要的,外表展现不过是对内容的包装,但真的将核心内容赤裸裸的暴露在大众面前,很多人会无法接受。因此,适当的包装对于很多人来说,还是很必要的。
  • 一切外表大过的内容的东西,难以长久。

听说今天是CSS裸奔节

2008年04月09日 13:17

我也凑凑热闹,裸奔一天

附页面截图:

naked_blog

From babyfish:

第三届CSS裸奔节来了,今年(CSS Naked Day ‘08)的时间定在4月9日。

活动目的CSS裸奔节的目的是推动Web标准。简洁为美。使用正确的(x)html,语义标记,良好的层次结构。暂时把页面设计抛弃,直接展示<body>吧。

假日观影

2008年04月07日 11:23

清明放假三天,彻底的放下了工作。补习了几部电影。

《长江7号》

之前看过听过很多对它的恶评,以至于看的时候心有惴惴。不过看完之后感觉还好。

说实话,这是一部挺幼稚的电影。对于电影本身,没什么可说的。但是看的时候,我突然想到些别的。

很多大人对着小孩子,都会要求那小孩子“来,笑一个”,“来,亲一个”,“来,走路看看”……。小孩真的那样做了,大人就会哈哈大笑。

小孩长大了,有自己的想法,开始玩过家家了。大人于是就无聊的走开,心里想着,这种无聊的小孩子玩意,谁要在乎呢?

殊不知小孩子自己是在乎的。他是在很认真的做着一件很幼稚的事情。我们应该尊重小孩子的这种认真。

小孩子不是为了逗大人开心而活。他们也有属于他们自己的想法和生活

在我看来,周星驰早期的电影,正是扮演了逗大家开心的角色。现在的他很认真的做了一部电影,虽然幼稚,但很认真。我们还是应该给予足够的尊重。

《罗拉快跑》

很早以前,看过海报。对罗拉的一头红发印象深刻。这次终于看完了这部电影。说实话,被《蝴蝶效应》近乎疯狂的多线结局熏陶之后,我对多线结局已经有了足够的免疫能力。因此对三段结局还没有感觉到太震撼。不过非常喜欢罗拉奔跑时的配乐和镜头运用。那是一种不同于好莱坞式镜头的新鲜体验。

尤其喜欢对每个人的那些闪回镜头。短短几秒钟就交待了一个完整的故事,在震撼之余,会忍不住想。我在路上碰到的每一个人,会有怎样的属于自己的画面呢?

结尾颇感意外。一直处于焦点位置的10万元,到最后突然失去了存在的意义。也许人生就是如此反复无常,你追求毕生的东西,也许到头来就是一场空。谁知道呢。也许我们应该享受这追求的过程,不是么?

《BeeMovie》

典型的好莱坞动画。但好笑的是居然让我看到了一些政治隐喻。那个被拉倒的熊罐,分明像极了萨达姆铜像。

将自己对世界的认知应用到他人的世界,由此带来严重的后果,这难道就是好莱坞对于伊战的反思么?

但愿是我曲解了影片本身。也许这个电影就是一个庸俗的动画片而已吧。

《牯岭街少年杀人事件》

要看完一部长达4个小时的电影,是颇需要下点决心的。

尤其杨德昌的电影,总是在不紧不慢的叙述中,将思想慢慢的输送给你,让你在乏味的体验之后,回头想想,感觉到背脊发凉。

不出所料,电影的前一个半小时,什么也没有发生。

要不是那些青涩、青春和叛逆勾起了我对往日的回忆,我几乎就要放弃了。

然而在枯燥背后,也隐隐的感觉到了一些什么。

果然,一个半小时之后,事情开始慢慢的显现出来了。

开始死人,开始流血。少年的世界,渐渐被成人的世界侵蚀。

最后小四用刀捅向小明的时候,我掩面长叹。

一部黑色的电影,没有光明的电影。这电影里其实谁都没错,那么到底是谁错了呢?

我突然很庆幸我居然活到了今天,还没有发疯。

历史上的今天

2008年04月01日 10:22

不用大家提醒,我也注意到了今天是愚人节。

也许有些人会觉得愚弄别人很开心,但因为曾经有被愚弄到留下心理阴影的前车之鉴,我并不太喜欢这个节日,更不希望在今天被人愚弄。

说点其他的吧。

1998年3月31日,愚人节的前一天,Netscape公司发布了Netscape Communicator 5.0的源代码,并成立mozilla.org。几经周折之后,2002年,Firefox从这里浴火重生。也许Firefox并不能称得上是一个完美的浏览器,但是正是因为它的出现,让那些原以为IE就是一切的用户们,知道了什么叫“web标准”,知道了更多更好的页面开发技术,也推动了停滞不前已经很久的IE又再次奋起直追,IE 7.0和即将推出的IE 8.0,也因此把对标准的支持,放到了一个很重要的位置上。原先存在很久却无人问津的ACID页面标准化测试,又被翻出来作为炫耀的卖点。

2004年4月1日,Google推出Gmail。在当时各个邮箱供应商纷纷缩减邮箱空间,甚至嚷嚷着说“收费才是唯一出路”的时候,免费的1G邮箱无疑是一个重磅炸弹。一年之后的又一个4月1日,Gmail又推出了“容量无限大+1”的概念,容量自动增长。到今天,Gmail的容量已经6G多了。虽然现在几乎所有的邮箱都跟当时的Gmail一样有超大的容量,有方便的用户界面,甚至做的可能比gmail更好。但是,正是Gmail,才让大家跳出了一个思维的定式,意识到“邮箱还可以是这样的”。

其实很多伟大的产品,它的伟大之处并不在于他自身有多么的优秀。再优秀的创意,总有一天可能会被人超越。但是当你接触了它之后,你的面前会开出一面窗,让你接触到原先你并不会去留意的美丽风景。也许想接触这美丽并不容易,你需要自己付出很多努力。但是,当你真的触摸到了窗外的美丽,你还愿意回到当初,面对四壁白墙么?

Design downloaded from free website templates.