现代软件工程讲义 5.1 软件的质量保证 (QA) 和测试 (Test)
在一个软件团队里, 不同的人有不同程度的投入, 我们在 猪,鸡和鹦鹉 的故事里已经说明了. 不同的人还要在团队中担负不同的任务:
开发人员 (大部分内容在: 现代软件工程讲义 2 工程师的能力评估和发展)
项目经理 ( 内容在这里)
测试人员 ( 本篇博客 )
团队中的管理人员/PM 负责分析市场, 设想功能, 定义用户到底要什么 – Why & What.
团队中的开发人员/Dev 负责实现功能, 搞清楚怎么才能满足用户的需求 – How.
团队中的测试人员/QA 搞清楚我们的软件是否满足了用户的需求 – Whether.
最后所有成员一块决定产品是否能发布, 什么时候能发布 – When.
测试/Test 和 质量保障/QA (Quality Assurance) 这两个词经常混用, 这两个概念是完全同等, 还是只是有一部分交集, 还是是另一个的真子集, 众说纷纭, 在各自的语境中, 都有意义。对于《现代软件工程》的语境, 我们这样规定:
QA: 运用各种手段, 在软件工程的各个阶段确保软件的质量能帮助软件团队实现目标。
Test (测试) : 特指验证代码的行为是否符合功能规格说明书 (spec) 的规定。
在这样的定义下, Test只是 QA 工作的一部分。
对测试工作的种种误解
一些人对“测试”这一工作还有很多误, 解例如下面的似是而非的观点:
1) 测试在项目的最后进行就可以了。
这是远远不够的。当你在项目后期发现了问题,问题的根源往往是项目早期的一些决定和设计,这时候,再要对其进行修改就比较困难了。这要求测试人员从项目开始就要积极介入,从源头防止问题的发生。有人会说,我是一个小小的测试人员,项目开始的时候我能做什么?这就是小小测试人员努力的方向。
2) 测试就得根据规格说明书(spec)来测,所以是很机械的。
那不一定,即使你的软件产品功能100% 符合spec 的要求,但是用户也可能非常恨你的软件。这时,测试人员就没有尽到责任,因为测试人员要从用户的角度出发,测试软件。
3) 测试人员当然也写代码,但是质量不一定要很高。
开发人员的代码没写好,可以依赖于测试人员来发现问题。但是如果测试人员的代码没写好,我们依赖谁来测试和改错呢?这就要求我们测试人员的代码质量特别高,因为我们是最后一道防线,如果我们的代码和测试工作有漏洞,那么Bug就会跑到用户那里去。
4) 测试只是被动地接受别人的产出, 然后开始自己的工作, 比较被动, 不能发挥创造性。
也许狭义定义下的 测试用例 是要等开发人员的代码, 然后开始测试。 但是整个质量保证工作(QA)需要前瞻性, 主动性, 创造性的工作。Weinberg 说过: “也许没有任何一项测试技术比前瞻性更有价值” (Probably no single testing technique is of more value than foresight.) [1]
各种测试方法
(注意到上图的黑箱子和白箱子了么? 它们里面装的都是测试的宝贝)
[下面的解释大部分来自于 《移山之道》 ]
7.1 基本名词解释及分类
统一思想要从基本名词解释开始。
1.Bug:缺陷软件的缺陷
Bug可以分为这三个组成部分:症状(Symptom)、程序错误(Fault)、根本原因(Root cause)。
(1)Symptom:即从用户的角度看,软件出了什么问题。
例如,在输入(3 2 1 1)的时候,程序错误退出。
(2)Fault:即从代码的角度看,代码的什么错误导致了软件的问题。
例如,代码在输入为某种情况下访问了非法的内存地址——0X0000000C。
(3)Root Cause:错误根源,即导致代码错误的根本原因。
例如,代码对于id1==id2的情况没有做正确判断,从而引用了未赋初值的变量,产生了以上的情况。
以下是一个完整的例子。
(1)Symptom:用户报告,一个Windows应用程序有时会在启动时报错,程序不能运行。
(2)Fault:有时候一个子窗口的handle为空,导致程序访问了非法内存地址,此为代码错误。
(3)RootCause:代码并没有确保创建子窗口(在CreateSubWindow()内部才做)发生在调用子窗口之前(在OnDraw()时调用),因此子窗口的变量有时会在访问时为空,导致上面提到的代码错误。
2.Test Case:测试用例
测试用例描述了一个完整的测试过程,包括测试环境、输入、期望的结果等。
3.Test Suite:测试用例集合
即一组相关的测试用例。
提示:Suite发音念作“sweet”,不是念作“suit”,一大半的学生都念错。
7.1.1 从测试设计的方法分类
测试设计有两类方法:Black box(黑箱)、White box(白箱)。
这是每个接触过软件测试的人都会给出的答案。但这只是整个软件测试的入门知识。可以跳过去,直接讨论下面的内容。
问:我在网上看到有人争论黑箱测试和白箱测试哪一个是另一个的基础,还有哪一个更难,哪一个更有前途,等等。据说河曲数码在搞“灰箱测试”,是不是更高级?能不能简单讲一讲?
阿超:大家都有这些问题么?
杂曰:[略去对此问题热烈的争论500字]
阿超:听了大家的争论,看来我们的确得花不少时间统一认识。
所谓黑箱/白箱,是指软件测试设计的方法,不是软件测试的方法!注意“设计”二字。
黑箱:在设计测试的过程中,把软件系统当作一个“黑箱”,无法了解或使用系统的内部结构及知识。一个更准确的说法是“Behavioral Test Design”,从软件的行为,而不是内部结构出发来设计测试。
白箱:在设计测试的过程中,设计者可以“看到”软件系统的内部结构,并且使用软件的内部知识来指导测试数据及方法的选择。“白箱”并不是一个精确的说法,因为把箱子涂成白色,同样也看不见箱子里的东西。有人建议用“玻璃箱”来表示。
在实际工作中,我们不应画地为牢,严格只用某一种方法来设计测试方法。在实际的测试中,当然是对系统了解得越多越好。所谓“灰箱”的提法,正是这一反映。有些测试专家甚至希望我们忘记全部的“箱子”和它们的颜色。
问:如果我是一个开发者,我能做“黑箱”么?
答:并不是要禁止懂得程序内部结构的人员来进行黑箱测试设计,只不过是在设计时有意不考虑软件的内部结构。例如:在测试程序内部基本模块的时候(单元测试),通常要求由对程序结构非常了解的程序员来设计,这是因为内部模块的“行为”和程序的外部功能并没有直接的关系,而且内部基本模块的“行为”通常没有明确的定义。另一个例子是“易用性测试”,在设计此类测试的时候,没必要纠缠于程序的内部结构,而是着重于软件的界面和行为。但是软件易用性测试也需要很多专业知识。这也从一个侧面表明“黑箱”和“白箱”没有简单的高低之分。
一旦测试用例写出来之后,大可以忘了它们是从哪种颜色的箱子里出来的,用它就可以了。
问:有人说“黑箱”,有人说“黑盒”,到底是“箱子”还是“盒子”?
答:在网上搜索了一下,“黑箱测试”有超过100万个记录,“黑盒测试”只有70多万。所以“箱子”赢了。
问:但是我听九条说他刚进公司实习的时候只能做“黑箱测试”,这是什么意思?
九条:我刚到公司实习的时候,两眼一摸黑,看到啥都是“黑箱”,即使测试用例是由懂得程序结构的开发人员写出来的,我还是只会机械地运行。我是知其然,不知其所以然,箱子当然是黑的。后来看得多了,学了一些东西,能够了解程序的结构和算法,箱子的颜色就变浅了,好像能看到箱子里的东西一样。
7.1.2 从测试的目的分类
1.功能测试
以下的测试术语主要是测试软件的功能。在表7-1所列的测试中,测试的范围由小到大,测试者也由内到外——从程序开发人员(单元测试)到测试人员,到一般用户(Alpha/Beta测试)。
表7-1 功能测试分类
测试名称 |
测试内容 |
Unit Test |
单元测试——在最低的功能/参数上验证程序的正确性 |
Functional Test |
功能测试——验证模块的功能 |
Integration Test |
集成测试——验证几个互相有依赖关系的模块的功能 |
Scenario Test |
场景测试——验证几个模块是否能够完成一个用户场景 |
测试名称 |
测试内容 |
System Test |
系统测试——对于整个系统功能的测试 |
Alpha/Beta Test |
外部软件测试人员(Alpha/Beta测试员)在实际用户环境中对软件进行全面的测试 |
2.非功能测试
一个软件除了基本功能之外,还有很多功能之外的特性,这些叫“non-functional requirement”,或者“quality of service requirement”——服务质量需求。没有软件的功能,这些特性都无从表现出来,因此,我们要在软件开发的适当阶段——基本功能完成后做这些测试。
如表7-2所示:
表7-2 非功能测试
测试名称 |
测试内容 |
Stress/load test |
测试软件在负载情况下能否正常工作 |
Performance test |
测试软件的效能 |
Accessibility test |
可访问性测试——测试软件是否向残疾用户提供足够的辅助功能 |
Localization/Globalization Test |
本地化/全球化测试 |
Compatibility Test |
兼容性测试 |
Configuration Test |
配置测试——测试软件在各种配置下能否正常工作 |
Usability Test |
易用性测试——测试软件是否好用 |
Security Test |
软件安全性测试 |
7.1.3 按测试的时机和作用分类
在开发软件的过程中,不少测试起着“烽火台”的作用,它们告诉我们软件开发的流程是否顺畅,这些测试如表7-3所示:
表7-3 烽火台
测试名称 |
测试内容 |
Smoke Test |
“冒烟”——如果测试不通过,则不能进行下一步工作 |
Build Verification Test |
验证构建是否通过基本测试 |
Acceptance Test |
验收测试,为了全面考核某方面功能/特性而做的测试 |
另一些测试名称,则是说明不同的测试方法,如表7-4所示:
表7-4 不同测试方法
测试名称 |
测试内容 |
Regression Test |
“回归”测试——对一个新的版本,重新运行以往的测试用例,看看新版本和已知的版本相比是否有“退化”(Regression) |
Ad hoc (Exploratory) Test |
随机进行的、探索性的测试 |
Bug Bash |
Bug大扫荡——全体成员参加的找“小强”活动 |
Buddy Test |
伙伴测试——测试人员为开发人员(伙伴)的特定模块作的测试 |
7.2 单元测试(Unit Test)
二柱:我们也试过用单元测试来保证质量,要求每人都要写,在签入代码前必须通过单元测试。但是搞了几个星期就不了了之。
大家七嘴八舌地列举了单元测试的问题:
◆ 有时单元测试报了错,再运行一次就好了,后来大家就不想花时间改错,多运行几次,有一次通过就行了;
◆ 单元测试中好多错都和环境有关,在别人的机器都运行不成功;
◆ 花在单元测试上的时间要比写代码的时间还多,提高代码覆盖率到90%以上太难了;
◆ 单元测试中我们还要测试效能和压力,花了很多时间;
◆ 我们都这么费劲地测了,那还要测试人员干什么?
阿超:看来问题还不少,我们留到后面再谈(见后面“单元测试”的具体描述)。
前面单元测试中提到代码覆盖率,简单来说代码被执行过,就是“覆盖过”,如果一段程序运行了一组测试用例之后,100%的代码被执行了,那么是否就说明再也不用写新的测试用例了呢?
(1)不同代码是否执行,有很多组合,一行代码被执行过,没有问题,并不表明这一行程序在所有可能条件的组合下都能正确无误地运行。
(2)代码覆盖不能测出还没有写的代码(缺少的逻辑)导致的错误。比如:
(4)代码覆盖不能测出时序问题,由时序导致的程序错误(例如:线程之间的同步)。
(5)代码中和用户界面相关的功能不能简单地以代码覆盖率来衡量优劣。
问:一个系统有这么多功能点,什么是基本的功能,什么不是基本的功能?
在运行BVT之前,可以运行所有的单元测试,这样可以保证系统的单元测试和程序员的单元测试版本一致。在不少情况下,开发人员修改了程序和单元测试,但是忘了把修改过的单元测试也同时签入源代码库中。
通过BVT的构建可以称为可测(Self-test),意思是说团队可以用这一版本进行各种测试,因为它的基本功能都是可用的。通不过BVT的构建称为“不可测”(Self-hosed)。
(1)找到导致失败的原因,如果原因很简单,程序员可以马上修改,然后直接提交。
(2)找到导致失败的原因的修改集,把此修改集剔出此版本(程序员必须修改好后再重新提交到源代码库中)。
方法(1)和(2)都可以使今天的构建成为“可测”,但是有时各方面的修改互相依赖,不能在短时间内解决所有问题,那就只能采用第三种方法了。
问:有人提到一种“Smoke Test”,冒烟测试,是怎么回事?
当所有的测试人员完成对场景的测试,我们自然地就得出了表7-5。
场景ID |
场景名 |
测试结果 |
Bug/小强ID |
3024 |
用户登录 |
成功 |
|
3026 |
用户按价格排序 |
失败 |
5032 |
3027 |
用户按名字搜索 |
失败 |
5033 |
…… |
…… |
…… |
…… |
这样就能很快地报告“功能测试56%通过”等。如果所有场景都能通过,(有些情况下可以把此标准从100%降低到90%左右)则这个构建的质量是“可用”,意味着这一个版本可以给用户使用。在这种情况下,客户、合作伙伴可以得到这样的版本,这也是所谓“技术预览版”或“社区预览版”的由来。
但是,有一个重要的问题要大家注意:“可用”,并不是指软件的所有功能都没有问题,而是指在目前的用户场景中,按照场景的要求进行操作,都能得到预期的效果,注意以下两种情况:
(1)在目前还没有定义的用户场景中,程序质量如何,还未得而知。
例如:场景中没有考虑到多种语言设置。
(2)不按照场景的要求进行的操作,结果如何,还未得而知。
如:在某一场景中,场景规定用户可以在最后付款前取消操作,回到上一步,如果一个测试人员发现在反复提交/取消同一访问多次后,网页出现问题,这并不能说明用户场景失败,当然对于这个极端的Bug,也必须找出原因并在适当的时间改正。
这种测试有时也被称为验收测试“Acceptance Test”,因为如果构建通过了这样的测试,这一个构建就被测试团队“接受了”。同时,还有对系统各个方面进行的“验收”测试,如系统的全球化验收测试,或者针对某一语言环境、某一个平台做的测试。
“Ad hoc”原意是指“特定的,一次性的”。这样的测试也可以叫Exploratory Test。
就是为了某一个特定目的进行的测试,就这一次,以后一般也不会重复测试。在软件工程的实践中,“Ad hoc”大部分是指随机进行的、探索性的测试。
“Ad hoc”也意味着测试是尝试性的,“我来试试,在这个对话框中一通乱按,然后随意改变窗口大小,看看会出什么问题……”,如果没问题,那么以后也不会再这么做了。
在一个团队中,“Ad hoc”太多是一个管理不好的标志,因为“Ad hoc”是指那些一时想到要做,但是以后也没有计划经常重复的测试计划。
答:有很多测试人员会按部就班地进行测试,但是还有一些人头脑比较灵活,喜欢另辟蹊径,测试一些一般人不会想到的场景,这些人往往会发现更多的小强。开发人员对这样的“Ad hoc”高手是又爱又恨。
问:看问题要分两方面,有些“Ad hoc”发现的小强在正常使用软件中几乎不会出现,我们要不要花时间“Ad hoc”?
“Ad hoc”测试的测试流程是不可重复的,因为它的测试都是“特定”测试,没法重复。由于这一原因,“Ad hoc”测试不能自动化,就这一点而言,还达不到CMM的第二级——可重复级。
问:我听说不少关于Regression Test的介绍,但是它到底是怎么“回归”法?回归到哪里去?我还是没搞懂。
答:Regress的英语定义是:return to a worse or less developed state。是倒退、退化、退步的意思。
在软件项目中,如果一个模块或功能以前是正常工作的,但是在一个新的构建中出了问题,那这个模块就出现了一个“退步”(Regression),从正常工作的稳定状态退化到不正常工作的不稳定状态。
在一个模块的功能逐步完成的同时,与此功能有关的测试用例也同样在完善中。一旦有关的测试用例通过,我们就得到了此模块的功能基准(Baseline)。
针对一个Bug Fix(拖鞋),我们也要作Regression Test。
(2)同时要验证新的代码没有把模块的现有功能破坏,没有Regression。
所以对于“回归测试”中的“回归”,我们可以理解为“回归到以前不正常的状态”。
7.8 场景/集成/系统测试(Scenario/ Integration / System Test)
在软件开发的一定阶段,我们要对一个软件进行全面和系统的测试,以保证软件的各个模块都能共同工作,在各方面都能满足用户的要求。这时的测试叫系统/集成测试。
问:有一种测试叫Scenario Test,是什么意思?
答:就是以场景为驱动的集成测试,关于“场景”,大家可以看专门的介绍。这一方法的核心思想是:当用户使用一个软件的时候,他/她并不会独立使用各个模块,而是把软件作为一个整体来使用的。我们在做场景测试的时候,就需要考虑在现实环境中用户使用软件的流程是怎样的,然后模拟这个流程,看看软件能不能达到用户的需求。这样,能使软件符合用户使用的实际需求。
以一个数字照片编辑软件为例,这个软件的各个模块都是独立开发的,可是用户有一定的典型流程,如果这个流程走得不好,哪怕某个模块的质量再高,用户也不会满意。用户的典型流程是:
(1)把照相机的储存卡插入电脑。
(2)程序会弹出窗口提示用户导入照片。
(3)用户根据提示导入照片。
(4)对照片进行快速编辑。
a. 调整颜色;
b. 调整亮度,对比度;
c. 修改红眼。
(5)选择其中几幅照片,用E-mail发送。
这里面哪一步出了问题,都会影响用户对这一产品的使用。如果这里面各个模块的用户界面不一致(即使是“确认”和“取消”按钮的次序不同),用户使用起来也会很不方便。这些问题都是在单独模块的测试中不容易发现的。
问:什么时候做集成测试?是不是越快越好?
答:原则上是当一个模块稳定的时候,就可以把它集成到系统中,和整个系统一起进行测试。在模块本身稳定之前就提早做集成测试,可能会报告出很多Bug,但是这些由于提早测试而发现的Bug有点像汽车司机在等待绿灯时不耐烦而拼命地按喇叭——有点像噪音。我们还是要等到适当的时机再开始集成测试。
问:但是开发人员也想早日发现并修复所有的Bug,软件工程的目标不就是要早发现并修正问题么?总是要等待,听起来好像没有多少效率。
答:对,这就要提到在微软内部流行的另一种测试——Buddy Test伙伴测试。
如上所述,在开发一个复杂系统的过程中,当一个新的模块(或者旧模块的新版本)加入系统中时,往往会出现下列情况。
(1)导致整个系统稳定性下降。不光影响自己的模块,更麻烦的是阻碍团队其他人员的工作。
(2)产生很多Bug。这些Bug都要被输入到数据库中,经过层层会诊(Triage),然后交给开发人员,然后再经历一系列Bug的旅行,才能最后修复,这样成本变得很高。
在项目的后期,签入代码的门槛变得越来越高,大部分团队都要求Bug fix必须得到了伙伴测试的验证后才能签入到代码库中。
7.12 内部/外部公开测试(Alpha Test, Beta Test)
在开发软件的过程中,开发团队希望让用户直接接触到最新版本的软件,以便从用户那里收集反馈,这时开发团队会在开发过程中让特定的用户(Alpha/Beta用户)使用正处于开发过程中的版本,用户会通过特定的反馈渠道(E-mail、BBS)与开发者讨论使用中发现的问题,等等。这种做法成功地让部分用户心甘情愿地替开发团队测试产品并提出反馈。
从惯例上说,Alpha Test一般指在团队之外,公司内部进行的测试;Beta Test指把软件交给公司外部的用户进行测试,与之对应地,软件就有Alpha、Beta1、Beta2版本。在网络普及之前,做Beta Test是很花费人力物力的事情,现在由于网络的传播速度很快,与外部用户的联系渠道很畅通,很多外部用户都想先睹为快。因此最近开发团队增加了反馈的密度,不必再局限于Alpha或者Beta发布,而是不断地把一些中间版本发布出去以收集反馈,美其名曰“技术预览版本”(Technical Preview Release)或“社区预览版本”(Community Preview Release)。
答:测试人员,以及其他的团队成员都可以对软件的可用性提出意见,包括以Bug的形式放在TFS中。软件的可用性并不神秘,就是让软件更好用,让用户更有效地完成工作。
为了弄清软件的可用性,并了解用户的需求,移山公司的员工特地进行了一个易用性测试——
王屋村的村民,石头他爹刚好路过,他被移山公司的小伙子们拉了进来,成为第一个“典型用户”。
大家七嘴八舌地介绍了游戏的功能,就让石头他爹试一试。石头他爹看到鼠标,说,这个怎么和俺家里的不一样?小飞说:这是光电鼠标,好用得很!
原来,石头他爹手指不灵活,在按鼠标的时候鼠标的位置会稍稍移动,导致程序无法捕捉鼠标双击事件。问题是在小飞设计的游戏中,鼠标单击、双击都可以,而且是不同的功能。
石头他爹看起来很迷惑。这时,小飞说:左键/右键/单击/双击都可以。
从此之后,石头他爹对每一个操作都问:是按左键还是按右键?是按一下还是两下?
半个小时后,大家送走了石头他爹,同时送他一个鼠标垫作为礼物。
阿超:幸好你还没有介绍你那超级功能,要按住Ctrl键,同时拖动鼠标才能使用。否则我们还要花半个小时陪石头他爹一起学习玩这个游戏。
问:我们已经讲了太多的测试了,好像微软还有一个叫“Bug Bash”的活动,是啥意思?
答:一般情况下是的,但是并不是全体人员用键盘鼠标一通乱敲乱点就可以搞定,大扫荡的内容也应该事先安排好。
◆ 鼓励测试队伍学习并应用新的测试方法,例如在做完“软件安全性测试”培训后,立马做一个针对“安全性”的小强大扫荡,或者为“全球化/本地化测试”做一个小强大扫荡也是很常见的;
7.15.1 十八般兵器
阿毛:超总,我的脑袋好像装不下了!听了这么多,我感觉像是身上扛着十八般兵器,它们互相碰撞,叮叮当当。我累得半死,但是不知道什么时候,对哪一种敌人用哪一种兵器,能不能总结一下!
阿超:好,我们用软件开发的生命周期来说明一下不同的测试在不同阶段的使用。
1.远景和计划阶段
此时,测试只是处于计划阶段,我们要讨论测试计划和测试设计说明书,同时要收集用户对于软件非功能性的需求,如效能、可用性、国际化等。一些“小强大扫荡”的类型也可以在这个时候初步安排。
2.开发阶段。
开发人员要写单元测试,测试人员要写BVT。
对于每一个成功的构建,测试人员要运行功能测试/场景测试,同时建立回归测试基准以便开始回归测试。各类测试人员要进行探索式测试以求尽早发现问题。
随着软件功能的逐步完善,测试人员要进行集成测试。这时,团队可以开展对程序非功能性特性的测试,如效能/压力测试、国际化/本地化测试、安全性测试、可用性、适用性测试等。在这个时候,可以考虑分析各个模块的代码覆盖率,以增加测试的有效性。根据计划,各种类型的“小强大扫荡”会以适当的频率发生。
3.稳定阶段。
到了一个开发阶段的尾声,这时测试团队就可以依据以前制定的验收标准,对软件逐项进行验收测试。按照测试计划,各个方面的测试都会宣布“测试完成”——所有想到的测试都做了,所有问题都发现了。在此阶段,团队也可以把软件发布给外部进行Alpha/Beta测试。
这时,伙伴测试会用于保证新代码签入前能得到足够的检测。
一般情况下,测试队伍要把迄今为止发现的所有小强都重新试一遍,确保它们都在最后的版本中被清除了,没有一个“回归”出现。
4.发布阶段。
测试队伍要把尽可能多的测试用例自动化,并为下一个版本的测试工作做好准备。
7.15.2 怎样写测试计划
这会在后面的章节中讨论。测试计划的模板在移山社区网站上有下载。
7.15.3 如果一个Bug在实际应用中根本不可能发生,这还是一个Bug么
看这里:http://www.testingcraft.com/Bug-in-forest.pdf。
另外,要知道这世界上有各种各样的用户,有些用户“亡软件之心不死”,IE和Windows的许多安全漏洞,都在这些用户的努力下被发现并且被利用了。很多人当初会说“缓冲区溢出?这是根本不会发生的事,用户怎么会在字符串后面加这么多乱七八糟的东西?!”。
7.15.4 Bug的数量和测试人员的工作效率有关么?和开发人员的工作绩效有关么
阿亨:当然有关!我们会在以后的实践中碰到这些问题。
阿超:有关,但是也不是太有关。一个极端的例子,如果一个开发人员写的模块没有任何Bug,那测试人员的工作效率如何衡量?我们以后再说。
7.15.5 有错不改
果冻:微软的产品经过这么多版本的不断完善,应该是把所有问题都搞定,“止于至善”了吧?
阿超:那也不一定,在非常有名的电子表格软件Excel中,就有这样一个Bug:Excel 的日期计算功能认为1900年是一个闰年,这是不对的,但是它愣是一直没有改正这个错误。
众人:真的?为什么屡教不改呢?
阿超:故事是这样的,当时这类电子表格软件的市场领头羊是Lotus 1-2-3这一款软件。它的日期计算功能有一个Bug,就是把1900 年当作闰年。这类软件在内部把日期保存为“从1900/1/1 到当前日期的天数”这样的一个整数。Excel 作为后来者,要支持 Lotus 1-2-3 的数据文件格式,这样才能正确处理别的软件产生的格式文件。这个错误就这么延续下来了,每一版本都有人报告,但是都没有改正。我们可以在Excel 中试试看:
在任意格子(cell)中输入“=DATE(1900,2,28)”,并且定义这个格子的格式为数字。大家可以看到数值变为:59。表明1900/2/28 是1900/1/1开始的第59天。
输入“=DATE(1900,2,29)”,可以看到 60! 这是一个不存在的日期!
输入“=DATE(1900,3,1)”,数值是61,事实上,这应该是60。从这一天开始的所有日期都错了一天。
果冻:还是可以抓住机遇,促成飞跃,在某一个版本彻底改好,不就是一个数字嘛。
阿超:改这个问题,技术上一点问题都没有。但是在现实中会出现下列问题:
(1)几乎所有现存文件的日期数据都要减少一天,所有依赖于日期的 Excel公式也要做检查和修改。这在现实生活中是很难办到的。
(2)Excel的日期问题解决了,但是其他软件还是有这个Bug,数据文件在不同软件中使用,就会有很头痛的兼容性问题。
总之,这个问题就这样一直留下来了。中间也有人想改过,你要注意看Excel 的 Options 设置,就会发现有这样一个设置——使用1904年开始的日期计算系统(use 1904 date system)(如图7-1所示),但是一般的用户谁没事在这里打一个勾?
图7-1
另: 关于闰年的bug 还有好些, 请看看这里: http://www.cnblogs.com/xinz/archive/2011/11/29/2267022.html
[1] Computer Programming Fundamentals, 2nd ed. (New York: McGraw-Hill, 1966) Herb Leeds, Gerald M Weinberg
转载于:https://www.cnblogs.com/xinz/archive/2011/11/14/2247980.html
现代软件工程讲义 5.1 软件的质量保证 (QA) 和测试 (Test)相关推荐
- 现代软件工程讲义 6 用户调研
[现代软件工程讲义 的一部分] 软件开发的过程, 就是 "用户最需要的东西" 在下面这一链条中传送,转换,实现,扭曲或丢失的过程. 用户最需要的 > 用户表达出来的 > ...
- 现代软件工程讲义 8 软件的血型
[这是 现代软件工程讲义 的一篇] 一个软件团队经历了计划/设计/开发等阶段, 达成代码完成 (Code Complete) 这一目标,似乎后面的事情就水到渠成了. 其实不然, 软件生命周期的最后阶 ...
- 现代软件工程讲义 1 软件工程概论
现代软件工程讲义 1 软件工程概论 几乎所有程序员都知道 "数据结构+算法 = 程序 " 这句名言.但是在实际的学习和工作中,也有不少人产生了疑问. 例如: 1. 我写 ...
- 现代软件工程讲义 9 测试 QA 的角色和分工
测试的角色 (Test) 要独立出来么 ? 独立出来的测试角色怎么才能发挥作用? 有些成功人士和成功的公司号称没必要有独立的测试角色 (Test), 你怎么看? 最近又看到一些关于开发人员要不要负责测 ...
- 现代软件工程讲义 5 项目经理 Program Manager
在一个软件团队里, 不同的人有不同的投入, 我们在 猪,鸡和鹦鹉 的故事里已经说明了. 不同的人还要在团队中担负不同的任务, 我们也要讲一下. 开发人员 (大部分内容在: 现代软件工程讲义 2 工程师 ...
- (转)五年教学实践与思考的结晶——推荐邹欣老师的《现代软件工程讲义》目录
(转)五年教学实践与思考的结晶--推荐邹欣老师的<现代软件工程讲义>目录 2011-11-28 07:15:21 按:自打2007年结识邹老师,出版他的第一本书<移山之道>,从 ...
- 现代软件工程讲义 2 工程师的能力评估和发展
Advanced Software Engineering 现代软件工程 讲义 软件工程师的能力评估和职业发展 介绍: 个人软件流程, 职业发展, 个人绩效的衡量和提高, 软件开发是科学, 工 ...
- 软件工程讲义 0 微博上的软件工程
[现代软件工程讲义] 有舌尖上的美味, 也有微博上的软工.舌尖上的美味各有千秋, 而微博上对软工的抱怨都是相似的. 下面是我在新浪微博收集到大学生对软件工程教学的反馈: 师生关系(不限于软件工程) 教 ...
- 软件质量保证计划_质量保证QA与质量控制QC
作者:郑文强 时间:2019年7月15日 关键词:质量管理QM(Quality Management).质量保证QA(Quality Assurance).质量控制QC(Quality Control ...
- 软件工程 | 第一章:软件工程学概述
软件工程学概述 一.前言 二.软件危机 1.典型表现 2.产生原因 3.消除危机途径 三.软件工程 1.概述 2.软件本质特征 3.软件工程基本原理 4.软件工程方法学 1️⃣传统方法学 2️⃣面向对 ...
最新文章
- spring mvc 与Struts的认识
- 啥?分布式啥?啥事务?
- 主分区活动分区扩展分区逻辑分区
- 切换图片 ImageSwitcher
- YOLO系列专题——YOLOv3理论篇
- 趣图:SQL 版的喝椰汁,没想到吧
- 大话移动通信(第2版)!(文末赠书福利)
- 树莓派查看CPU温度
- 龙芯电脑开启串口的console控制台配置
- yolov5-4.0转caffe记录
- c# 指定打开某个路径下的CMD_Windows小技巧 批处理文件实现目录下文件批量打包压缩...
- Dell T7920工作站 拆装硬盘
- 高校教学管理信息系统/教学管理系统
- EI收录中国大陆期刊名录(2012年)
- 原生Js通过class属性值获取对象
- python实现电话号码映射
- J2EE达内18天笔记
- 富芮坤FR801xH使用SDK开发蓝牙GATT协议栈教程
- 谈谈LTE 4G技术(by quqi99)
- OceanBase SQL 执行计划解读(二)──── 表连接和子查询
热门文章
- 【高德LBS开源组件大赛】回眸微博的足迹
- 一个邮箱联结全球?也许不会是遥不可及的梦想
- 数据结构-图的应用-最小生成树(类C语言版)
- java 美发管理系统_美容美发管理系统毕业论文.doc
- 在LINUX环境下怎样设置无线网络配置
- 那些惊艳了岁月的诗词
- linux系统live管理界面,5个你应该知道的Live Linux桌面发行版
- 【iOS】 app 的优化
- NOIP初赛知识点总结
- KTL 一个支持C++14编辑公式的K线技术工具平台 - 第五版,支持sqlite3,全新sqlite3zz语法超简单使用sqlite3; 添加方差等统计函数。