软件测试和验证是细致活也是辛苦活,需要模仿终用户尝试各种用法和输入场景、比较并断言所期望的行为。而这些细致的辛苦活是可以让计算机程序去做的。自动化测试套件中那些可编程部分对于大规模软件交付是非常有帮助的。在我做过的大部分项目里,有些测试是可以自动化的,也有些不能。不过,只要有自动化测试套件,我的团队都将倚重于它,而将精力集中在那些没有自动化的功能测试。而且,自动化测试还让我们能够满足客户快速变化的需求,并使我们达到了一个更高的层次,使得每次构建(即使只是微小变动)都是经过测试和验证的稳定版本。正如Jez有关持续交付的文章中所言,自动测试“让交付团队超越了基本的持续集成”并走上持续交付的康庄大道。实际上,我觉得自动化测试是非常重要的,如果你要实践持续交付,必须在自动化测试上进行投入。本文解释了之所以我这么认为的原因。

      时间周期 - 从后一次代码提交到发布

      当软件复杂度不断增长时,验证其变化部分和已构建部分的工作量都会随之增加,这种增长至少是线性的。这意味着测试时间与需要验证正确性的测试用例数量是成比例的。因此,增加新特性即意味着从开发完成到交付软件的时间会拉长,如果投入更多测试人员来应对增加的工作量(假设所有测试任务是相互独立的),那么交付成本也会增加。很多团队通过保留一个测试人员池来应对这一问题,这票人马在整个发布版本验证期间都在做“回归”测试,以检查新变化是否破坏了已有功能,我待过的一些团队也是这么干的。但是这么做不仅成本高昂,而且效率低下、进展缓慢且容易出错。

      在自动化测试场景下,你可以减少花在验证用户功能工作上的时间和金钱。我们不妨假设你的测试场景中有合理数量的测试用例是可以自动化的,比如50%,这通常是软件项目可自动化测试用例的下限。如果你的团队能够自动化该数量的测试用例,那么人们可以将把更多注意力集中于那些新近变化的特性上。假设跑一遍这些自动化测试需要3小时(时间越短越好,甚至少于20分钟),这一时间将直接影响将产品推出的时间。增加自动化测试的数量,并尽量减少测试运行的时间,那么你快速响应的能力将显著提升,同时成本得到缩减。下面我用一些简化数字(平均用例数)加以说明:

      团队A

      1、需测试场景数量 - 1000且在增加中。

      2、建立构建环境所需的时间 - 10分钟。

      3、测试一个场景所需的时间 - 10分钟。

      4、团队中的测试人员数量 - 5。

      5、假定不存在blocker(阻塞)。

      如果没有自动化测试,测试单次提交的时间总量为(以分钟计):

      10 + (1000*10)/5 = 2010 分钟。

      接近于4个工作日(每工作日8小时)。如此不仅成本高昂,而且开发人员在4天后才能得到反馈。这种设置日后还有可能在你的迭代中形成迷你瀑布。

      团队B

      与团队A的情况相同,但是测试套件中有50%的测试用例自动化了。假设运行完这500个自动化测试用例需要3小时时间。

      现在,测试单次提交所需的时间总量为(以分钟计):

      任务1(手工) - 10 + (500*10)/5 = 1010 分钟。

      任务2(自动) - 10 + 180 分钟。

      接近2工作日。这虽不十分理想,但足以证明减少了成本,我们可以测试完之前的构建。测试开销减少了一半,我们还在3小时内完成了50%的测试用例。

      接下来是更加理想且是可以达到的状况。

      团队C

      与团队B的情况相同,但是我们把测试放在更好的机器上运行,这样速度更快(比方说20分钟),而且80%的测试都自动化了(10%不能自动化,另10%是新功能)。

      现在再来看,测试单次提交的时间总量为(以分钟计):

      任务1(手动) - 10 + (200*10)/5 = 410 分钟。

      任务2(自动) - 10 + 20 minutes = 30 分钟。

      结果,我们在30分钟内覆盖了80%的测试,大约7小时即可结束整个测试。更值一提的是,在30分钟内跑完80%的测试,可以让我们尽早发现blocker,以便暂缓进一步手工测试。这样的话测试成本低、反馈快,在很大程度上改变了测试的过程,不是吗?

      每次发布的测试成本

      自动化不仅缩短了周期,还大大缩减了每次发布的成本。成本减少源自两个方面:

      通过自动化测试尽早给开发人员反馈,提升了所测构建的质量,让他们得以收获“绿色”构建。 
      测试成本直接减少,因为反复运行相同测试的人员减少了。 
      测试成本直接减少比较容易解释清楚。以上面我们所提到的团队为例,下列图表显示了在运行所有测试时各个团队所花费的成本;这里假定每位测试人员每小时需花费50美元。

      如你所见,对某一发布的候选构建做一次全面测试,团队A的花销(10万美元之多)几乎是团队C的5倍。

      如果周期更长的话,比如说2年,那节约下来的成本相当可观了。如果目标是之内能够跑完一遍发布构建测试的话(这一目标不算过分),那么团队C已经达标。团队A需要25个测试人员才能达到该目标,而团队B则需要15人。下面,我还要增加进硬件和编写程序的成本,来说明自动化测试对于一个超过2年的发布周期的有何意义:

      硬件成本 - 机器及其他共5万美元

      编写程序成本 - 再投入2个开发人员,初2个月编写自动化测试程序,剩余时间维护测试套件,那么团队B和团队C的人数现在是7个。

      针对这一数字,为了达到每天测试一遍构建这一目标,在2年时间里团队A的成本有四百八十万美元之巨。相比之下,团队C的成本接近一百四十万美元,成本减少了70%。从下面的图表可以更直观地看到这一点:

 

      除了在缩短周期和减少成本上发挥作用外,自动化测试还创造了很多间接价值,包括:



      验证及时

      如果要再2小时内完成一个构建的验证,前面提到的团队A需要50名测试人员,但客户不会对这块成本感兴趣。如果没有自动化测试,大多数情况下,之内完成验证到交付几乎是不可能的。之所以这么说,是因为这种情况下成本极其高昂。因此,如果我的团队没有自动化测试,也没有无限资金的话,即便开发人员只提交一行代码,我们完整验证一个构建的时间也会成小时甚至成天的增加。这样的话,管理人员对每次构建都完整运行测试的积极性会下降,终导致构建测试覆盖面下降,对系统中bug的测试时间减少。另外,我还遇到过因此而减少代码提交频率的情况,这样并不健康。

      反馈频繁、快速

      自动化重要的一个方面是团队从构建过程中可以得到快速反馈。每次提交都进行了无预判测试,团队很快能得到测试报告。反馈越快则意味着建立在有错代码之上的代码越少,进而提高了软件可靠性。仍以上面的团队A、B、C为例:

      对于团队A - 第发现blocker的概率是1/2,这意味着测试第二天找到bug的风险比较高,这样的话第的工作全浪费了,因为这个blocker修正之后所有测试都需要重新验证一遍。坏的情况是这个bug在代码提交两天之后才发现。
对于团队B - 坏的情况是在这后几个小时才发现blocker。这也比团队A的情况好得多。而且,由于50%的测试用例是自动化测试,在3小时之内发现blocker的几率非常高(50%)。这种快速反馈可以让你更快发现并修正bug,因此响应客户需求的速度也非常快。
对团队C - 这三个团队中情况好的。坏场景是团队C在3小时之后才知道他们是否提交了blocker。因为80%的测试用例都进行了自动化,20分钟他们能知道是否有错误。从团队A到团队C有很长一段路要走,但20分钟比2天要好得多。
机会成本

      经济学家使用一个贴切的术语 - 机会成本来定义在多种选项中选择其一时将会失去的东西。 对一个又一个构建反复验证那些乏味的测试用例,其机会成本是:失去了花在探索性测试上的时间。机会成本通常不在于一个bug导致多个bug的情况,而在于对手工测试投入过多精力,这样的话测试人员很难找到时间来创建新的测试场景并跟进问题。不仅如此,由于所有时间都集中在回归测试上,测试人员在新功能上投入时间不足,然而从这些新特性中找到bug的概率却是比较高的。通过尽量自动化测试用例,可以释放测试人员的大部分精力,让他们做更具创造性的任务,并从“人的角度”去探索应用程序,以增加测试覆盖深度和质量。在我做过的项目中,只要有自动化测试辅助手工测试,测试得都比较深入,因而质量也比较高。

      手工测试还包括乏味地、日复一日重复验证相同测试用例的工作,这是手工测试的另一个缺点。即便每天把测试分配给不同的人也是有创造性的活动,过一段时间之后,每轮测试也只是重复而已。测试人员鲜有时间去做创造性工作,因此他们对工作也缺乏满足感。测试人员是有创造性的人,他们的长项是以终用户的角度去使用软件并找到新的方法来测试并发现应用程序的问题,而不是不断的重复一套过程。如果没有自动化测试,留住好的测试人员并让他们满意的机会成本是非常巨大的。

      减少人为出错

      不管你信不信,的人同样也会在日常工作中犯错。工作做得好,犯错的机会少一些,但是出错的机率还是大于0。在检验构建质量过程中,对人为出错的风险了然于胸是非常重要的。实际上,软件应用大部分bug背后都隐藏着人为错误。相反,计算机做这些重复性任务效率极高 - 它们既勤奋又细心,通过自动化测试可以减少人为错误风险。

      测试是可执行的文档

      测试场景是应用程序状态一个的知识来源。如果想了解应用程序能为终用户做些什么,手工测试结果可以提供一个很好视图,并且告知开发团队其代码中哪些部分比较“古怪”。所记录的测试结果由两个部分组成 - 展示应用软件能做什;记录什么会出错,怎么出得错。有了这些信息,很容易管理应用程序的异常举动。如果测试人员很勤奋,可以保证文档总是新的(另一项开销),可能看一下测试结果会知道软件的状态。但随着错误量的增大,工作量会大幅增加,作为测试人员需要记录操作步骤,抓取屏幕快照甚至是崩溃情况下的视频。如果在这些事情上花时间多了反而会增加变更的成本,实际上由于成本太高,人们不太愿意在每次发布时都记录状态。

      有了自动化测试,通过选择正确的工具,记录应用程序状态的成本明显降低了。自动化测试工具提供了很好的方式来执行测试、按类别收集结果并把结果发布在Web页面上,让你能够直观看到测试结果数据以监视测试进度并从测试结果数据中获取相关反馈。使用类似Twist,Concordian,Cucumber等工具的话,给用户展示测试结果甚至让他们来编写测试都变得相当容易;这样既减少了信息传递过程中的损失,也让用户能更深地介入到应用开发过程中。对于测试失败的结果,多数测试工具都自动化了抓取屏幕快照及视频的过程,以更有意义的方式记录失败和错误。测试结果可以邮件方式发送给测试人员,还有更好的:每次构建都以RSS feed的形式提供给感兴趣的人。

      技术层面测试(Technology facing tests)

      测试应用程序的非功能特性??比如响应用户动作的性能,测试网络延迟及其对终用户与应用程序交互的影响等等,传统上都是部分自动化(尽管我早期曾经干过用秒表来手工测试性能的活,低保真但有效)。我们可以很容易利用自动化测试并重用它们来做非功能性测试。例如,多次重复运行一个自动化测试可以告诉你Web页面上某个动作的平均性能 。该模型很容易建立,将功能性自动化测试的次数输入所选的框架内,那么在测试运行过程中你可以建立并探测非功能性属性。要测试并监视例如基于较色的安全、延迟的影响、查询性能等,都可以通过重用已有的自动化测试来自动化,这是自动化测试额外的好处。

      小结

      在持续交付的过程中,不论大小,你都必须采取诸多步骤。其中难逾越的障碍是在减少测试周期同时保持较低成本。自动化测试能帮你做到这些,同时让你建立起更加高效、快乐的团队,他们是在开发过程中进行测试。我的理解及建议是:从小处着手,充分投入以建立一套健壮的自动化测试套件,给它配备的人,培养团队尊重测试及结果的习惯,先建立起一个主干,然后逐步细化,平稳过渡。