摘要
  持续性能测试能够帮助开发团队尽早处理难以诊断的性能及负载问题,并尽早发现重大功能缺陷。在灵活性、覆盖度、有效性方面的优势,使得性能测试成为持续测试的一个好选择。
  持续集成的一个重要原则是降低改动所需耗费的时间并及早发现改动引起的问题。我们经常把这个原则称为“快速失败”。通过持续集成,开发团队得以迅速查清问题根源,而不用像以前那样等几周甚至几个月才开始测试。
  要实现持续集成,开发和测试团队必须定期运行一套自动测试,并且这套自动测试的覆盖率要足以发现重大缺陷。如果测试范围太小,就会遗漏很多严重问题;如果测试时间太长,测试人员要花费很多时间才能发现缺陷。这就是为什么我们在敏捷开发中要持续推行自动化测试
  根据我的观察,在持续集成的环境中,满足了三个主要因素,就能够大幅提高测试团队的效率:
  灵活性:测试在任何需要的时候都能运行。
  覆盖率:在允许的时间内,尽可能提高测试的覆盖率。
  有效性:测试要及时发现难以定位的产品缺陷。

  几年前,当我刚开始接触持续集成和持续测试时,相关的讨论主要围绕单元测试功能测试。开发团队在代码中加入单元测试,测试团队开发出一小部分可以按需运行的功能测试自动脚本。但是性能测试大多数时候还是要等到项目快结束时才开始。大家认为,功能测试的完成,得以确保足够的产品质量,性能测试才不会遇到功能性问题。
  通过试验、观察、项目进度控制上的教训,再加上一点运气,我们发现提早并多次进行性能测试可以显著提高性能测试的价值。一方面得以在项目早期阶段就发现棘手的问题,另一方面也增强了已经进行的功能测试的效果。
  只要看一下上面提到的三个因素,就很容易知道原因:性能测试通常都可以满足这三个因素。因此,把性能测试纳入持续测试中会是一个不错的选择。
  灵活性:性能测试是自动化的
  性能测试本质上来看,几乎总是可以被自动化的,因为手动方式很难确保高负载和大容量的测试环境。和采用自动化测试相比,用鼠标连续点击“提交”按钮一万次,困难得多也更难以重复。
  正因为性能测试所固有的高度自动化特性,使得它们可以在任何需要的时候被执行,不受周末及节假日影响。有了这样的灵活性,临下班前提交的改动也得以在晚上运行自动化测试,而不必等到测试与开发团队第二天的上班时间。
  覆盖率:性能测试快速覆盖多数功能点
  性能测试通常都能在不过分深入功能点的前提下,提供足够的主要功能覆盖率,它能在短时间点执行到大范围的常用功能。如果在主要功能点中存在缺陷,那它往往就会在性能测试中被捕获。性能测试人员常会是最早发现大的功能缺陷的人。虽然这并不意味着持续性能测试可以或应该替代自动化功能测试,但是性能测试确实为功能验证提供了有力的辅助。
  要当心不要让性能测试实际成为功能测试,而导致团队忘记测试的重心是在性能问题上。然而,共同进行功能测试和性能测试,确实可以有效找出产品存在的缺陷,不让这些问题成为测试中的拦路虎。
  有效性:性能测试尽早发现难以定位的产品缺陷
  管理性能测试团队的另一个重要经验是:性能问题很少由专门针对性能的代码改动引起,换句话说,性能相关的缺陷主要存在于看起来无关紧要的代码中。往往是,改动了某段代码,执行一次时只对性能产生非常小的影响,但是执行成千上万次后,就会积累形成严重的性能问题。
  让我们来考虑一种看似无害的情况。某行代码的改动仅引起了每次循环10毫秒的性能延迟,假设这段代码在单个事务中要循环10次,此时性能延迟成了100毫秒,即1/10秒。如果我们希望每秒运行上百次甚至上千次事务,这个看似非常小的性能延迟就会积累起来,严重降低系统每秒可以处理的事务数。
  假设开发人员在周一做了以上的代码改动(自然,他的初衷并不是针对性能的),并从周二开始别的代码开发工作。测试团队在两周后介入,发现了这个问题。此时开发人员已经进行了两周的开发,引入问题的开发人员的工作重心已经转移到别的四、五个模块上。很可能当初的代码改动太小,他甚至忘记了自己当时有做过这样的改动。由于问题被发现时已经是在缺陷被首次引入的两周后,开发人员和测试人员需要花费大量时间精力,很艰难地才能发现问题的根源。
  再考虑一下另一种场景:测试团队进行了可持续的性能测试。测试人员每个晚上都进行同样的性能测试,那么在周二早上就会发现周一晚上的测试比周末的测试结果要差。由于每天都会进行性能测试,开发人员只需要排查周一的代码改动就能发现问题所在。
  这里的关键点在于,功能改动是有意为之的,它是被设计为对系统做出相应改动的;但是不利于性能提高的改动却很少是有目的性的,更可能是其他有意为之的功能改动所造成的无心之过。
  在问题首次引入到测试发现问题之间间隔的时间越长,定位并解决这些使得系统性能下降的无心“副作用”就会变得愈发困难。如果性能测试在几周甚至几月内都没有进行,对类似的性能问题进行根源分析几乎成为不可能。尽早发现这类性能问题可以使得开发人员更好地发现根源问题并解决缺陷,从而帮助开发和测试人员在这样大海捞针的任务上少花费时间,而是把更多的精力集中在完善发布的产品的质量上。
  扩展性能测试
  如果你还没有做性能测试,现在就开始吧!即便是最基本的性能测试,持续运行也能带来重大收益。从单一的事务开始,将一组测试输入/数据作为测试的参数,并使用JMeter或Grinder之类的免费工具来扩展事务规模:每次增加一个事务,直到该样本包括了系统中的重要事务为止。现在的测试工具比以前的更容易使用,而且以前被认为是高级的功能在现今的多数基本工具中就有了,比如参数化、验证系统响应、生成分布式负载、简单报表等。
  如果你已经在做性能测试了,但只是偶尔运行或在项目收尾阶段才运行,可以从已经执行的测试中选一部分来每天运行。如果受到测试环境等条件的限制,也要尽可能多地运行性能测试,哪怕每周或更久跑一次也好。关键在于选出可以重复运行的测试,并减少两轮执行之间的时间,尽快地发现问题。记住:“持续”的含义并不是“不间断”。
  持续性能测试的结果要让相关人员很方便查看。我建议使用仪表板(dashboard)来给出性能测试最新进展的概要报告,如果需要可以进一步查看更详细信息。
  最重要的是,要让测试和开发人员都参与进来,审查测试结果。就像那个森林里的树倒下却无人知晓的古老寓言,如果性能测试在大叫“出问题了,出问题了!”,却没人听到,那么这样的测试还有意义吗?
  结论
  找到并修正性能问题本身就是一个非常困难的任务,更不用说要从几周甚至几个月的代码改动中苦苦寻找问题根源。如果我们能缩短问题被引入和问题被发现之间的时间,那么就可以简化排除问题的过程,避免打击士气,让团队将更多时间花在完善产品总体质量上。 因为同时具备了高灵活性、高覆盖度和高有效性的优点,性能测试往往是持续测试的有力候选项。