第4章 开发者眼中的可测试性
可测试性(Testability)对于不同的人会意味着不同的东西,这取决于情景(Context)。从高度抽象角度来看,可测试性是与被测软件以往的体验有关系的,也与我们对缺陷的容忍程度有关:一个已经运行了5年的电商网站,可能需要较少的测试,它会比第一次安装胰岛素泵所需做的测试要容易得多。如果我们运行一个项目,可测试性将意味着获取必要的信息、保证资源(如工具和环境)和有充分时间来执行各种测试。另外从知识的视角看:我们了解产品和所用技术的程度如何?我们的测试技能有多好?我们的测试策略是什么?可测试性还有一种理解是通过可靠的规格说明书和确保用户参与其中,以建立一个大家对产品的共识。除非了解产品的预期行为,否则我们很难测试任何产品。
在详细解释可测试性对开发者意味着什么之前,让我们看看为什么实现软件的可测试性也就意味着软件的完成。
4.1 可测试的软件
可测试的软件(testable software)将促进测试的存在,无论是手动测试或自动测试。软件的可测试性程度越高,人们测试它的机会也就越多,也就是说,人们会验证了它的行为是否遵守需求和相关期望,或带着一些目标去探索软件。一般来说,人们在他们的工作中遵循着阻力最小路径,如果测试不在这条路径上,它们很可能不被执行(见图4.1)。
可测试的软件将有更多的机会进行某种测试,这一点是显而易见的。同样显而易见的是,如果软件缺乏可测试性,这一点常常伴随着时间压力而发生,它可能导致一个满是缺陷和破碎的软件。
可测试的软件是天平的一个极端,而"大泥球的软件"(The Big Ball of Mud Foote&Yoder 1999)是另外一个极端。
有一些代码,可能让你怀疑,这些代码是人为反对可测试性而故意设下的陷阱,用于难为你的工作和生活。如果你与一个大泥球架构的系统打交道,真正的后果是无法验证代码的效果。由于各种原因,例如复杂的配置、不必要的启动时间或难以产生某种状态或数据,你可能真的很难执行所编写的代码,更不用说为它写的任何类型测试!
举例来说,想象一个系统,要求你在用户界面登录后,执行一系列步骤,其中你需要与各种图形组件进行交互,然后浏览多个视图后才能达到你刚刚更改或添加的功能,并需要对此进行验证。为了让例子更加贴近现实(是的,这是现实生活中的一个例子),进一步想象一下这样的场景--由于一些糟糕的设计决策,启动时间受到了严重影响,导致出现登录屏幕需要 4 分钟。再举另外一个例子,想象一个批处理程序,必须在一定条件下运行20分钟,才能满足代码的一个特定路径。
图4.1 不可测的软件是否需要被测试?
老实说,如果你必须在一个用户界面的多个域中输入值,并需要点击几个屏幕来验证新代码(先不说等待应用程序启动),这种情况下,你打算验证多少次?或者仅仅运行一次?再比如,如果你想验证在某些特殊情况下批处理程序工作是否正常,你是否需要每次运行的时候都来一杯咖啡以打发等待时间?
大泥球架构系统的测试人员面临着一项艰巨的任务。他们的测试用例往往是从一个非常长的说明开始,介绍如何将系统设置为测试所期待的状态。这需要一个脚本,用于说明如何填充界面中的内容,或如何对20分钟的批处理进行系统设置。测试脚本的作者不仅仅需要创建脚本,并且使其足够详细,他们还必须遵循其详细步骤进行操作……许多许多次,如果他们不太走运的话。嗨!
4.2 可测试性的好处
除了有助于免除开发人员和测试人员当前的痛苦,可测试的软件还有一些其他吸引人的优点。
4.2.1 功能可被验证
如果软件被开发出来,其行为可得到验证,这样我们就非常容易确认软件是否支持某种功能,在某些输入条件下,其行为是否正确,是否符合具体的协议接口或满足一些非功能性约束。解决一个缺陷其实就是这样一个过程:定位缺陷、修改代码并运行测试。这个过程是固定的,并且可以预测的。与其完全相反的是玩猜迷游戏。
查利:业务规则X在情况Y下适用吗?
凯特:不太清楚!在5.21的版本,是不是业务规则X取代了业务规则Z?
查利:不知道,好像不在5.2的发布版本中?我记得这功能太慢,并且有问题,而我们是在5.4才取代的。
凯特:这可真难住我了,毫无线索。
如果软件的功能是不可验证的,而是通过猜测来描述,那就很可能发生以上的对话。缺少可测试性将导致这些猜测和时间耗费。因此,这种情况下,功能很有可能没有被完成。
因为没有人负责可测试性,一些软件的功能可能只是通过口头相告或只是出现在组织的指标牌上。这些功能可能会"迷失",甚至更糟的是,功能可能会被臆想,人们会开始期待某些功能会在那里,即使这些功能根本就不存在。所有这一切都将导致"这不是一个错误,它是一个功能"的争论和相互指责的游戏。
4.2.2 减少意外
对于任何一种软件项目管理的方法,在某一时刻,有人总会想查看软件开发的进展,例如已经做了多少工作?还剩下多少工作?这样的检查不需要很正式,也不需要写入里程碑、阶段报告或者甘特图(Gannt)的书面报告 。在敏捷团队中,开发者将通过每天的站会或类似的会议,沟通他们的进展。
然而,对于一个没有测试(由于可测试性差) 的软件进行预估进展 ,这种预估很可能天马行空或一厢情愿。如果一个开发人员宣称对一个功能有"95%完成度",他很可能无法预知他可能破坏了一些其他功能,无法得知需要花多少时间修复回归问题和处理剩下的"5%"工作。系统性的测试可以使这种情况更易于管理。再次,如果该功能是所谓的"95%完成"和新功能的所有测试都通过,以及系统其他部分也通过了测试,这种估计将是非常可信的。现在,对于剩余的工作,潜在的意外和不确定性将大大减少,而不会再出现系统中任何地方都可能出现的随机回归问题。当然,这里假定了代码功能确实是被测试所覆盖,实际上也可能会发生回归问题。
4.2.3 它可以改变
软件可以随时被改变。其中关键是需要以合理的成本和安全的方式进行。假定可测试的软件暗含着测试,这些测试的存在使得软件被修改时,人们不必担心软件变化而引起副作用--破坏软件。
不断变化的软件,如果没有测试,会让大部分开发人员感到不舒服和害怕(这是必然的)。这种恐惧很容易在代码中被观察到。它体现为大量重复的申明--一种避免破坏软件工作的安全方法。当人们进行代码回溯时,我们有时可以找到以下情况的证据:
在某个时间点,开发人员需要一个特定的功能。唉,有没有什么十分类似的代码。开发人员不再使用已有的概念或通过归纳或参数化,而是选择创造一个安全的代码路径和并行实现,它的错误只会影响新的功能,而系统的其余部分将不受影响。
这只是一种重复的形式。事实上,这个话题是很复杂的,值得用一整章篇幅来写清楚。
相关文章:
版权声明:51Testing软件测试网获人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。