Defects的启示

在过去的几个月,我做了一些实践,通过整理、讨论和分析项目上的Defects情况,来探索质量管理中的待改进点。最终发现,Defects实际上给质量管理带来了很多的启示。

当然,要讨论Defects,首先要使团队对Defects有一致的理解。我查了很多资料,也没有找到对”Defects”一词的明确定义,大部分人将”Defects”等同于“Bug”。

1947年9月9日,Grace Hopper发现了第一个电脑上的bug。当团队在Mark II计算机上工作时,搞不清楚为什么电脑不能正常工作了。经过深度挖掘,才发现,原来是一只飞蛾误打误撞地飞到了计算机内部,从而引发了故障。从此,人们开始用“Bug”(原意是“虫子”)来称呼计算机中的隐含的错误。

然而,一个好的软件产品,不仅要关注功能本身,还要关注其是否好用、是否安全、是否给用户带来良好的体验、是否帮助用户实现真正的业务价值。因此,从狭义上讲,Defects是指软件程序中存在的某种破坏其正常运行的问题或错误。从广义上讲,Defects还包含那些没有达到客户或用户期望的质量问题。具体来说,Defects可以分为以下几类:

  • 程序错误: 指程序中存在某种错误,比如边界、时区等问题,使得系统无法正常工作。
  • 性能问题:指由于性能瓶颈所导致的系统缺陷。试想,作为用户,如果你想要查看一个报表,却需要花10分钟来等待加载,你是否会放弃?
  • 安全问题:指软件安全漏洞,造成信息泄露、或使得系统数据或功能易受攻击。
  • 兼容性问题:指程序无法在不同的硬件平台、操作系统、网络环境等中正常运行。
  • 功能与用户需求不否:指软件功能与用户期望不匹配。比如,用户期望造一个沙发,却交付了个马扎。
  • 交互体验不佳:指用户使用起来不方便。譬如,电梯控制面板上的“报警”按钮和“关门”按钮紧挨在一起,你是否经常由于”关门”而误触了“报警”按钮?再比如,你在网页中填写了一个长长的表单,点击“提交”按钮后,系统提示输入信息有误,却并没有告诉你错误的哪里,你是会不耐烦地从头查阅,还是干脆放弃?

Defects的产生与应对策略

产品质量是团队共同的责任,软件开发是一个过程,任何环节都有可能产生质量问题,但每个环节的问题都应该选择比较恰当的处理方式。

在敏捷开发中,我们以迭代的形式逐步完成产品的开发,每个迭代都能以一个可交付的软件呈现给用户,从而尽早地获得用户反馈,以保证我们交付的软件是用户真正期望的。在每个迭代中,我们所有的开发都基于用户故事卡(Story),每一张用户故事卡都将经历Analyse、Design、Code、Test、Deploy的过程。

那么,在敏捷软件开发过程中,哪些环节都可能产生Defect呢?

正如上图所示,Defect分别来自于Sprint阶段、UAT用户验收阶段以及真正的生产环境。其中,Sprint阶段又细分为:不合理的需求、不恰当的设计、代码及逻辑错误、Story卡测试过程中发现的问题、回归测试中发现的问题、以及非功能性测试发现的问题。

开发过程中不同阶段的Defects,我们分别采用什么样的敏捷实践来应对呢?

上图以看板的形式展示了Sprint开发中Story卡片流动的过程,以及每个环节的敏捷实践,这些实践有助我们发现和改善质量问题:

  • 不合理的需求: 由于QA往往有不同于BA的视角,提早与BA Pair完善Story AC (Acceptance Criteria)。此时发现的问题要及时补充到Story卡上。这样,不仅能够尽早地发现需求上的不合理或遗漏,还有助于QA深入理解需求、设计测试用例。
  • 不恰当的设计:UX制作出酷炫的设计图,却并不一定是用户真正期望的,或者技术实现的成本过高。因此,一方面,要在开发之前与用户Review设计图,并按照用户的反馈及时更新;另一方面,在每一张Story卡开始开发之前,由BA、UX、QA及Dev一起Kick Off Story,通过讨论和澄清,使得团队成员对需求和设计达成一致。一旦发现问题,要及时更新Story卡和设计图。
  • 代码及逻辑错误:单元测试、Code Review、Desk Check都是用来发现代码及逻辑错误的有效手段。因此,开发提交代码后,要先执行单元测试、只有当单元测试通过之后,才可以将代码部署到QA测试环境;然后按照Story的AC逐条与QA和BA进行Desk check。除此之外,开发团队要每天坚持Code Review,以便发现代码逻辑及编码规范方面的问题。这些过程中发现的Defects都应该尽快修复。
  • Story卡测试中发现的问题:Story卡测试时发现的问题,无论其严重程度如何,基本上都要在当前迭代修复。QA可以与Dev面对面沟通,也可以将Defect添加到Story的Comment里面,再将Story重新拖回In Dev状态,或者在物理看板上添加一张物理卡片。但无论哪种形式,都需要在早会时提及,以便有效地跟踪Defect进度。
  • 回归测试中发现的问题:普遍来讲,回归测试发现的问题,优先级要低于Story的开发。因此,QA需要在电子看板或者Defects管理系统中提交一条Defect记录,然后与BA沟通,在最合适的时间Assign给Dev。但如果该Defect造成系统崩溃或者Block了某些功能的使用,就应该立即修复它。
  • 非功性测试发现的问题:非功能性测试一般是在每个Release上线之前做,发现的问题也要在Release之前修复。同样需要在电子看板或者Defects管理系统中提交Defect记录,但要注意其优先级。
  • UAT用户验收阶段的反馈:在UAT阶段,开发团队向用户Showcase,或者由用户来做用户验收测试。此时,用户会提出一些反馈。由QA和BA对这些反馈进行分析,如果是功能层面的问题,在看板上建成卡片,并在上线前修复。如果是需求层面的问题,就将其添加到需求列表中,以便安排在之后的迭代计划中。
  • 生产上的问题:生产上的问题优先级是最高的。但是与用户反馈一样,功能层面的问题要立即修复,用户体验上的问题要添加在需求列表中。

Defects对质量管理的启示

Defects并不是独立存在的,它或多或少反映出了项目管理和开发过程中存在的问题,这些问题都可能对质量产生影响。比如:线上问题的走势,是否能够反映出产品质量的变化;分析每个迭代Defects的数据及产生的原因,有助于发现开发过程中出现的问题,及时地进行风险把控。

我以自己所在项目为例,说一说Defects给质量管理和团队管理带来的启示。

1. 通过线上问题走势,分析产品质量的变化

2017年8月,我们接到A遗留系统,到10月份累计在生产环境发现历史遗留问题21个。按照优先级,每个月修复一定的数量。截止2018年7月,发现的历史遗留问题高达46个,只剩余2个还未修复。Defects数量在减少,产品质量在逐步提升。

除此之外,我们对历史遗留问题和新引入问题做了对比,这10个月的线上问题中,历史遗留问题占85%,新引入问题占15%,可见仍有部分没能在开发过程中发现,使其流到线上。要对这些问题具体分析:其严重程度如何、产生的原因是什么、为什么在开发过程中没有发现、后续有怎样的改进措施。 当然,最好能对生产上的“运维类问题”和“功能类问题”加以区分,以便采取更恰当的改进措施。

2. 分析迭代Defects情况,讨论改进措施

除了分析线上问题,我还对从2017年10月-2018年7月QA提交的Defects情况做了一个统计,观察每个月提交的Defects和修复的Defects情况。

从统计结果来看,2018年7月发现和修复的Defects数量均呈明显的上升趋势,达到历史最高点。因此,有必要对7月份的Defects情况做一个详细的分析,看看究竟是什么原因导致了这些Defects。

我对这些Defects做了一个初步的分类,并利用Retrospective Meeting的机会,与团队成员一起分析讨论。发现产生问题的原因有以下几个方面:

  • 本次Release的Story Kick Off和Desk Check做的不够好。有时候开发没有Kick Off就直接按照自己的理解开始编码,导致团队成员没有对需求达成一致的理解,做出来的功能出现偏差。有时候Dev将一堆卡垒在一起做Desk Check,这样很难逐条覆盖AC,从而将问题流入QA测试阶段。
  • 本次的需求比较偏技术,BA只能从业务的角度去编写Story卡。开发同学为了追赶工期,没能够添加充分的Tech Task, 也没能够坚持Code Review,导致出现一些逻辑错误。
  • 单元测试覆盖率比较低。作为一个遗留的微服务系统,某些服务在之前从未重构过,代码逻辑比较混乱,添加单元测试的难度大、成本高。因此一些本该单元测试阶段就能发现的问题一直流到QA测试阶段。
  • 本次Release一共一个月时间,UI一直到最后一个礼拜才确定下来,期间反反复复的修改不仅花费了太多成本,还消磨了Dev的意志,导致出现一些本不该出现的Defects。
  • 新人加入,项目工期紧,对上下文信息同步不够,导致新开发的内容破坏了一些已经验证过的功能。

这些原因充分说明了这段时间项目中存在的问题,我们对此逐条提出了具体的改进措施:

  • 坚决执行Story Kick Off和Desk Check敏捷实践,在每日站会时严格跟踪每一张Story卡的进度。
  • 预定一个定期会议,每天下午17:00 – 18:00进行Code Review,并每周一人轮班担任Owner。
  • 将单元测试覆盖率可视化。同时,制定项目标准:对于新开发的内容,必须编写并通过单元测试才能Desk Check;对于历史遗留模块,在技术债墙上添加技术债卡片,并于每周消化一个技术债务。
  • 项目开发前期要加强与客户和用户的沟通,在Story开始开发之前,确定好UI设计,开发过程中尽量避免大的改动。
  • 新人加入项目时,采用结对编程的方式完成开发。除此之外,每周在项目内进行一次技术分享Session。

当然,以上两点只是我基于A项目举的一个例子。实际上,Defects还给了我们很多启示,比如,为什么项目老是加班?为什么有些模块的Defects数量比较多?如何根据团队成员花在Defects上的efforts,制定提升计划?然而,每个项目的情况不一样,我们应该基于自己的项目背景,由团队成员一起分析深层次的原因,共同制定切实可行的改进措施,从而不断地提高产品质量。


更多精彩洞见,请关注微信公众号:思特沃克

Share

数字化时代的软件测试

数字经济高速推动着一个无情的市场,所有利益相关者通过设备和应用网络进行交互,一个微观时刻足以让市场领导者摆脱优雅。 这种对速度的痴迷能否淡化质量定性方法?《World Quality Report 2017-1028》带你来一探究竟。

Quality Report

现代QA和测试部门重点关注的领域

敏捷和DevOps已经成为数字化转型的重要工具,同时,质量保障和测试工作也随之发生变化:

  • 中央治理和控制减少,团队选择方法和技术的自由度增大;
  • 部署速度提高和应用程序日益复杂化,软件错误和故障的风险增加;
  • 软件质量对品牌的影响巨大,但这已经不是最高优先级的目标,日趋成熟的尽早质量保障实践可以帮助纠正品牌和形象方面的缺陷;
  • 最终用户的满意度和安全性是最重要的两个方面,要确保应用程序的功能和非功能质量,同时需要找到成本和风险的平衡点。

调查结果表明,现代QA和测试部门需要重点关注的领域是以下三个方面:

1. 智能测试自动化和智能分析

智能测试自动化和智能分析将成为支持测试的关键,因为它们可以实现智能决策,快速验证和自动调整测试套件。测试自动化的范围从简单地将测试活动(计划、设计和执行)自动化发展到自动化测试环境和测试数据配置。

然而,调查结果显示目前自动化还处于不足的状态,尽管从自动化中获益的组织数量在增加,但产生的价值没有根本变化,测试自动化水平仍然很低(低于20%)。

速度将推动更智能的自动化需求,需要找到提高自动化水平的方法。

2. 智能测试平台

智能测试平台需要应对测试环境、数据和虚拟化日益增长的挑战。真正的智能测试平台的远景超越了生命周期自动化,需要实现自动配置的完全自我感知和自适应环境,以及支持自动化测试数据生成和测试数据管理。

测试环境、测试数据和虚拟化是三大挑战,同时也为自动化提供了巨大的机会。结合智能生命周期的自动化,将使QA和测试进入下一个演进阶段,称之为智能QA,这已经成为行业重要的关键成功因素。

3. 适应敏捷开发流程的QA和测试部门

组织需要关注的第三个领域是适应敏捷开发流程的QA和测试部门。在敏捷和DevOps模型中,测试从中心部门转移到分散的团队。未来的测试组织需要将灵活性与效率和重用性相结合,提供测试环境、测试数据、测试专业知识和技能的测试中心将分散到各种业务线的IT团队。

FIGURE 1

QA和测试的现状与挑战

从调查结果,总结出以下关于质量和测试现状的发现:

1. 回归对应用程序质量的关注,表明在敏捷环境的新上下文里,测试已经成熟

面对开发和测试环境的复杂性以及数字化转型的速度,关注点正在回归到整体产品质量上来,这是一个进步的迹象:

  • 参与这次调查的受访者中QA和测试人员明显多于其他角色,由2016年的37%上升到2017年的41%;
  • 2016年被引用最多的目标是在上线前发现缺陷,这个数字从40%下降到2017年的28%;
  • 最终用户满意度从39%下降到34%。

客户体验和增强的安全性处于IT战略的前两位。从2016年到2017年,增强安全性需求从65%大幅下降到35%。 IT成本优化进入今年IT战略的前三位,证明QA和测试能够应对过去几年的快速变化。

其他一些对IT战略意义重大的领域包括对业务需求的响应、实施软件即服务以及实施敏捷和DevOps。敏捷和DevOps实施需求的减少幅度超过一半,从38%的受访者减少到17%,这表明这些开发方法正变得越来越主流。

2. 测试自动化正在通向智慧、智能和认知QA之路

自动化尚处于待开发阶段,测试活动的平均自动化水平约为16%。自动化产生的价值在很大程度上没有变化。测试自动化不仅应该复制现有的手动测试过程,38%至42%的组织将认知自动化、机器学习、自我修复和预测分析视为测试自动化未来的有前途的新兴技术。

智能解决方案是DevOps、移动和物联网中的新趋势。通过增加智能自动化,企业适应快速变化的业务环境能力将得到增强。

Test Automation

3. 敏捷开发中测试的挑战不断增加

  • 99%的受访者在敏捷开发测试中面临某种挑战
  • 46%的受访者认为缺乏数据和环境是最严峻的挑战,这比2016年的43%有所提高
  • 在敏捷迭代中重复使用或重复测试的难度排在第二位,由2016年的40%增加到了45%
  • 挑战数量下降的唯一领域是:难以确定测试的重点以及测试团队在计划或初始阶段的早期参与。

测试和测试环境的自动化将帮助组织解决敏捷和DevOps开发模式给测试所带来的大部分挑战。 这些智能测试解决方案使得质量保障的速度能够适应日益复杂的集成IT环境。

4. QA组织不断演进以满足双峰要求

2017年,集中式的测试组织和分散式模型之间的分配更加均衡。在许多组织中,以前的卓越测试中心(TCoE,Test Center of Excellence)已经过渡到更加灵活的测试卓越中心(TEC,Test Excellence Center),其重点在于支持和赋能,而不是实际执行测试活动。

瀑布式开发仍将在未来很长时间内实施,形成与敏捷和DevOps混合的局面。例如,组织选择定位软件开发测试工程师(SDET)的位置时,其中敏捷Scrum和TCoE分别是36%和47%。

5. 环境和数据仍然是QA和测试的难点

调查结果显示有73%的组织采用云环境、15%的组织采用容器化来执行测试,使得测试的生命周期缩短。然而,仍有50%上下的受访者分别表示在测试环境管理、测试环境利用率、适用于敏捷开发的开发和测试环境,以及早期进行集成的环境方面存在挑战。

在测试数据管理方面,分别有超过50%的受访者存在以下挑战:管理测试数据集的规模、创建和维护合成测试数据、遵守与测试数据相关规定。

Test Environment Management

6. 测试预算下降,但预计会再次上升

专门用于质量保证和测试的IT总支出的比例为26%,它已经从2016年的31%和2015年的35%下降。

但是,随着组织采用敏捷和DevOps来支持数字化转型,未来两年质量保证和测试预算将会增加,企业必须确保IT应用程序的数量和复杂性,以及随之而来的QA平台解决方案的质量。

推荐的应对策略

1. 提高智能测试自动化水平

自动化是满足日益增长的数字化转型测试需求的关键,建议组织制定一个中心战略,确定企业首选的测试工具,确定自动化计划的战略业务目标,并确定衡量结果的指标。

同时,引入基于分析的自动化解决方案,向智能化QA和智能化测试自动化转变,以确保能跟上数字化转型的速度,做到持续的发展。

2. QA和测试部门转型以支持敏捷开发和DevOps团队

首先是组织结构方面的转变,QA需要与Dev和Ops团队一起,构建集成的DevTest平台,以实现持续的测试自动化。

测试人员专业技能也需要有所改变,要加强开发、分析和业务流程方面的技术专长,以适应敏捷和DevOps模式。

3. 投资智能测试和质量保障平台

在日益复杂的IT环境下,智能测试平台有助于企业做好质量保障工作。

  • 将智能分析和机器人解决方案引入测试流程和平台;
  • 提高容器化和虚拟化解决方案的水平和使用;
  • 投资于测试数据生成解决方案,以提供更多更好的符合所有法规的合成测试数据;
  • 将容器化环境,虚拟化服务和自动化测试数据集成到一个共同的可访问流程和平台中,组织可以围绕所有测试活动制定一致的方法;
  • 采用持续监测,预测分析和机器学习工具,利用生产环境数据,提供基于业务风险和实际问题定义测试策略。

平台战略

4. 定义企业级测试平台战略

开源和服务化解决方案给质量保障和测试工具的选择带来了灵活性,但是,跨多个存储库数据连接和交换导致企业级质量状态缺乏透明度。

企业可以实施单一平台战略,指定一些技术为主要选择工具,或者创建最佳工具策略,可以涉及来自不同供应商的多种工具解决方案。

5. 定义企业级QA分析战略

前面提到过智能分析是重点关注的领域之一。为了从智能QA(智能测试自动化和智能测试平台)的投资中获得最佳回报,建议组织确定企业范围的QA分析策略。

这种质量保证分析策略决定了应该部署分析和认知解决方案的目标和领域,定义了跨QA操作的智能技术路线图。质量保证分析战略应与整体组织战略相联系,并应描述其如何实现整个组织目标。

:以上内容和图片均摘自《World Quality Report 2017-1028》,更多详细内容请参考原文。


更多精彩洞见,请关注微信公众号思特沃克

Share

打造企业级移动测试云平台

背景

移动技术发展到现阶段,原生、混合式技术发展的足够成熟,可以无缝融合。而随着移动技术的发展和革新,移动领域的测试技术和实践也有了一定发展:工具不再像早期一样几家独大,选择性越来越多;从浅尝辄止的实验阶段到真实项目中的自动化测试落地。这些实践在一定程度上提升了测试反馈效率,在迭代交付的过程中出色的完成了质量保证的工作,但在相对漫长的实践过程中,我们依然可以总结一些痛点:

1、移动自动化测试的执行效率远不及Web应用

有过Web自动化测试经验的同学对于Selenium肯定不会陌生,Web端的并发测试使得测试在有限资源的情况下按照我们的期望并发执行。而且由于keychain等问题,很难在测试用例之间做到互不影响、对于测试环境的清理和准备也有很大难度。

2、很难全面覆盖繁杂的测试设备

Web自动化测试关注的测试环境相对单纯,针对不同项目、产品和市场,无非是对不同的浏览器和操作系统有不同程度的支持。而对于不同浏览器也有不同的driver来支持。而在移动测试中,很难做到对众多厂商和不同操作系统设备进行模拟。

3、移动自动化框架很难支持到回归测试颗粒度

在移动端(以iOS为例),受限于Apple的机制,大部分框架很难覆盖到与iOS系统/第三方App交互的场景,例如系统通知跳转、实时通讯应用信息发送等场景。而若无法覆盖核心功能,那么自动化测试的落地实则是在给自己和团队挖坑,得不偿失。

这些问题在随着WebDriverAgent的成熟以及XCode 9的新特性 —— Multiple concurrent simulators的出现,得到了极大程度的解决,我们可以像对Web应用一样,对移动端应用在不同的simulator上并发执行测试用例,极大提升了测试反馈效率。而且,测试人员不再受限从而可以编写覆盖率更高的测试用例。

除了普适性问题之外企业对移动测试方案潜在需求?

在项目的具体实施过程中,除了我们经常被这些普遍存在的细节问题困扰之外,企业或组织级客户已经对移动端自动化测试提出了更高的要求。在一次机会给客户讲解移动端自动化测试趋势时发现,新的框架的确会使客户眼前一亮,但是,在实践上的优势无非是你比其他人先研究了什么,这样的领先微乎其微,在交流过程中观察到客户更大的痛点是:

如何同时覆盖到更多物理设备?如何更好的构建和重用基础设施?如何跨地域高效使用测试资源?

带着这几个问题,我们对比了一些现有的可用方案,例如AWS device farm。Device farm是针对移动App提供的测试服务,用户可以对在AWS托管的基于iOS和Android物理设备测试原生和混合应用。用户既可以使用各种测试框架来做自动化测试,也可以远程访问设备进行应用程序的测试和调试。

但是该解决方案也是有一定局限性的,当测试运行期间同时执行测试的设备最大只有五个,而运行测试的时间也被限制到60分钟。当然上述的限制可以根据需要适当的放松,但是企业和用户不得不承担价值不菲成本。

与AWS device farm类似,SauceLabs和Xamarin也提供类似的平台,那SauceLabs的服务举例,如果想使用无限运行时间,支持24个并发运行设备,模拟器用户需要每月承担3576刀,而如果想使用真实设备进行测试,大概需要每月花费7200刀。这种昂贵的成本对于企业很难承受,而且重要的是这种资源是无法复制,企业不得不持续为云服务支付高昂的费用。

安全性也是企业需要考虑的问题,用户不得不在云测试平台上传自己的IPA或APK。我们当然可以信赖AWS的安全机制。一些对安全性要求较高的企业来说,更想规避这样的风险。

打造私有移动真机测试平台

通过分析,对于客户的需求大概涵盖几点:真实设备、并发、成本、安全、可重用。鉴于这些需求,我们把目标进行拆分:

1.设备管理——服务发现与注册

在该实例中我们使用WebDriverAgent作为测试框架,需要运行在每一个物理设备上,我们可以把这些物理设备当作Agent集群。这些集群设备就是我们运行WebDriverAgent的服务终端,我们可以通过很简单的程序让WebDriverAgent自动在设备上运行。通过服务发现与注册机制,把WebDriverAgent服务注册在通过Ansible管理的Proxy上。而服务发现与注册不单单解决了复杂的设备管理,而且可以解决分布式团队合作时设备跨地域有效利用的问题。

2.平台数据可视化

对于一个测试平台来说,如何把所有可用的服务(机器)、服务状态、自动重启和crash报告等数据可视化给企业终端用户,是极为重要的。那老牌Apache zookeeper来说,提供了友好的服务可视化管理功能并且可以根据用户需求进行二次开发。重要的是,这些底层基础设施服务可以在之后的任何一个移动测试项目中被重用。

3.自动化测试运行和报告生成

自动化测试平台虽然提供了强大的服务(设备)管理、服务可视化等功能。而自动化测试的核心需求依然是如何保障测试的独立性、稳定性、易维护性、重用性和覆盖率。通过WebDriverAgent跨语言测试框架,我们可以像架构Web自动化测试一样来开发针对移动端的测试工程。但需要注意的是移动测试不同的是真实物理设备,而不是计算机的某个进程。另外,如何接触测试场景的相互依赖、保证测试间的独立性,以及如何清理测试环境,需要大家在进行移动端架构的时候事先考虑。

这样一来,我们如果可以解决这三个问题,就可以不受昂贵的成本限制,为企业量身定做适合自己的业务规模的移动测试私有云了,不但为企业和组织机构构建了大型测试服务平台,同时也解决了之前提到的普适性问题。

总结

随着DevOps的发展,软件工程的开发、部署、上线、应急预案等都被自动化监控和处理。如果我们依然停留在“成熟”的解决方案而缺少思考,那么留给QA/测试人员的发展空间越来越少。

我们需要通过对测试技术细节的不断归纳、对比和练习,抓住领域发展趋势和真正的客户诉求,结合其他非测试技术,帮助自己在测试技能上有所突破,同时帮助自己提升构思和落地解决方案的能力。


更多精彩洞见,请关注微信公众号:思特沃克

Share

性能测试问题与思考

性能测试对于大部分测试人员都是一个神秘地带,因为在很多公司,性能测试都是由一个性能测试团队来做,所以普通测试人员没有机会接触到真实的性能测试,因而很难学习到很多新的测试实践知识。

市面上现在有非常多关于性能测试的书籍,其中不少书籍都能够系统地介绍性能测试。今天我想通过另一种方式来介绍性能测试,那就是通过提出一些关于性能测试的问题,然后针对问题进行思考。希望通过不一样的方式让读者以另外一种视角来思考和学习性能测试实践。

1、如何在敏捷开发中做性能测试?

敏捷开发,由于其持续集成、快速反馈等特点,需要性能测试工具支持轻量化、集成CI服务器、全代码化等特性,所以传统的性能测试工具比如JMeter和LoadRunner等已经很难适用于敏捷开发。在敏捷开发中,性能测试应该需要具有以下特点:

  • 性能测试是持续集成和持续发布的一部分,尽可能早的发现性能问题,从而降低修复成本。这样可以使得很多性能问题在开发过程中被持续的尽快发现。建议将性能测试写成故事放到每个迭代里面去,见下图:
  • 性能测试脚本易读,易维护。比如代码化的脚本GatlingLocust等。下面是Gatling的DSL示例代码:
  • 可视化,报表易读,每个人都能及时了解状况 。下图为Jenkins集成了一个Gatling插件后所展现的Gatling持续测试报表。

通过在敏捷开发中做持续的性能测试,使得性能测试也可以:小步快跑->快速反馈->持续改进->持续交付。

2、如何通过数据分析更有效的做性能测试?

大部分情况下大型项目的性能测试需要的时间和人力都非常高,因为:

  • 用户并发要求高,测试硬件成本高
  • 测试功能点多,测试量大
  • 耐久性测试,测试时间长

其次是测试的有效性差,因为测试人员在测试环境中很难模拟真实用户的操作,比如访问的顺序分布,访问的强度分布以及用户端的各种访问参数。

为了解决这两个问题,应该通过用户数据分析来获得真实的用户行为数据,并用其来构造性能测试用例,其中可以用下面这个漏斗模型来进行思考:

通过这个漏斗模型可以知道,为了快速得到真实有效的性能测试数据模型,需要通过筛选并整合真实的用户数据,而并不是靠测试人员在实验室中想象出来的数据。

那如何进行用户行为分析呢?下面尝试用三个例子来进行说明。

第一个例子是一个用户注册流程,通过用户行为的数据分析可以得到每个功能点上用户的访问量。见下图:

图中展示了用户注册流程的6个步骤,分别是:

  1. Getting Started
  2. Account Information
  3. Personal Information
  4. Financial Information
  5. Review Information
  6. Thank You Page

其中第一个步骤有18606次访问,然后有71%的访问用户选择继续,但是只有13131(70.6%)到达了第二个步骤。最终只有925(5%)的用户完成了注册。由此可以知道不同步骤的真实访问比例,从而得到性能测试的数据模型和策略。

第二个例子是用户使用的浏览器的数据统计,如果性能测试需要模拟不同的浏览器,那么这些数据分析结果也可以用以确定浏览器在性能测试中的权重。

通过这个统计表可以知道使用IE浏览器的用户最多,所以在生成性能测试数据的时候应该多生成一些基于IE浏览器的数据,比如User-Agent等。

第三个例子是统计的用户访问地区,对于有些大型的互联网应用是需要进行多地区模拟来测试不同地区互相访问时的性能。这个数据统计结果可以帮助其设计更有效的这类性能测试用例。

通过这个统计表可以知道英国的用户访问量最多,而美国的访问量第二。如果应用服务器部署在美国,那么就应该尽可能的在英国架设测试服务器,通过在英国的测试服务器来测试美国的应用服务器,从而测试跨国网络的性能,并且还需要在产品环境检测英国到美国的网络性能,从而及时发现性能问题。

通过对这些真实用户数据的分析,可以设计更有效的性能测试模板,下面是一个性能测试模板的样例,其中每个功能点上圆圈中的数字代表这个功能点在真实环境中的用户访问权重。权重越大的功能点在整个性能测试模板中应该测试量更大,所花费的成本更高。

常见的Web系统用户数据跟踪与分析工具有:

  • Adobe SiteCatalyst:功能强大,使用繁琐,收费(贵)
  • Google Analytics: 功能较强,使用方便,免费和收费
  • 百度统计/腾讯分析:功能一般,免费

使用数据分析来生成数据模型的流程如下:收集数据->分析数据->生成测试数据模板->使用数据模板。

3、对大规模集群系统做性能测试应该注意什么?

通常中小型公司的IT系统都不使用大规模的集群,而只有大型公司才会大规模使用集群,导致很多测试人员没有机会实践和了解基于集群的性能测试。如果想学习基于集群的性能测试,除了常规的测试集群系统性能以外,还可以从以下几个方面进行思考,从而学习基于集群系统的性能测试:

  • 测试环境的真实性,由于大规模集群包含很多节点和服务,所以搭建和产品环境一样的测试环境的成本很高,导致测试环境的规模一般都比产品环境小很多。那测试这样的测试环境还有什么意义?
  • 一般集群都会使用负载均衡,但是由于存在多种负载均衡算法和配置,那么怎么才能保证负载均衡功能是按照设计和配置的进行工作?
  • 除了对集群系统进行整体的性能测试外,还需要单独对不同的服务和节点进行性能测试吗?

所以针对集群系统做性能测试不仅仅能测试系统的性能,还可以解决以上三个问题:性能规划,配置测试,隔离测试。

性能规划

对于一个大型的服务器应用系统,一般情况下都是由规模化的集群组建而成的。所以测试这类基于集群的服务器系统的时候,也需要将测试环境配置成和产品环境类似的集群系统。不过因为成本的原因,测试环境中的集群规模大都要小很多。可以通过测试小规模的集群,然后使用其测试结果,并通过数学建模推算产品环境的性能或者对产品环境进行性能规划。由于每个集群系统拥有各自不同的架构,配置和服务,所以其数学模型也是不同的。

配置测试

通过更改集群系统的各种配置,并在不同的配置下对集群系统进行性能测试,从而获得最优配置。比如辅助开发人员完成集群功能的开发与验证,比如负载均衡算法,热备等;以及辅助运维团队配置和调试产品环境的集群配置等。

隔离测试

对于集群系统的服务或者节点,开发这些服务的团队应该在隔离(stub)第三方依赖的环境下,各自对自己团队开发的服务进行独立的性能测试。从而尽早发现性能问题,尽早修复,避免在集群环境下发现同样的问题,增加调试和时间成本。

大规模集群系统基本都是复杂架构,环境也都是较为复杂的组织结构,而只有深入理解整个业务流程,系统架构以及环境结构才能有效地设计测试方案。

4、性能测试中的测试数据有几种类型?

测试数据一直是软件测试中的一个头疼的问题,特别是在性能测试中测试数据尤为重要,因为越真实的数据越能获得更好的结果。对于测试数据的类型可以分为以下四种:单一型,随机型,模板型,真实型。

单一型

它是通过录制或者观察,使用一个或者一类单一的测试数据来进行性能测试。这种数据的构建简单,但是数据过于单一,无法模拟真实用户。由于其数据构建简单,所以可以用于敏捷开发中的早期性能测试。

随机型

它是通过一些简单的数据规则,并结合随机算法生成的测试数据。这种数据和单一型比较,虽然增加了随机性,但是仍然缺乏真实性,并且其构建成本和性能问题的分析成本也相对较高。它可以用于上线前的大规模的多样化的综合性能测试。

模板型

它主要是通过数据分析并生成模板来构建测试数据。虽然它较随机型在一定程度上增加了用户真实性,但是准备数据的成本很高。在项目成本和资源允许范围内,可以结合模板型和随机型的方法,从而更为有效的进行性能测试。

真实型

它是通过直接导出或者重定向产品数据来做性能测试数据。它完全是真实的用户数据,构建成本较低,但是存在数据安全性的问题,比如数据泄露。在数据安全性可以得到有效保护的情况下是可以使用真实型数据来进行性能测试。

测试数据生成和管理对于一个大型项目的性能测试是十分重要的,所以如何高效的生成有效的测试数据成为了首要的任务。通过这四种测试数据类型,可以快速的判断在项目当前阶段适合使用那种类型的数据,从而避免一些弯路。

5. 其他问题

除了以上问题和思考,我还准备了一些其他的基本问题给读者自己去思考,从而通过思考问题来学习性能测试。

  • 性能测试主要包含哪些类型以及分别的作用是什么?
  • 前台页面的性能测试应该注意哪些问题?
  • 对于并发用户很少但是稳定性要求很高的系统需不需要做性能测试?为什么?
  • 对于后台有大量异步批处理需求的系统应该怎样进行性能测试?
  • Profiling是不是性能测试?什么时候应该做它?
  • 常见的性能测试工具有哪些?怎么选择性能测试工具?
  • 如果测试环境和产品环境的硬件配置不同,如何通过测试环境的测试结果评估产品环境的性能?
  • 在设计性能测试用例时需不需要考虑Think Time?
  • 中小型项目的性能测试都需要注意些什么?
  • 性能需求的来源有哪些?
  • 如何使用云服务进行超大规模性能测试?

更多精彩洞见,请关注微信公众号:思特沃克

Share

聊一聊契约测试

什么是契约

如果从契约产生的阶段来说,现有资料表明最早要追溯到西周时期的《周恭王三年裘卫典田契》,将契约文字刻写在器皿上,就是为了使契文中规定的内容得到多方承认、信守,“万年永宝用”。所以订立契约的本身,就是为了要信守,就是对诚信关系的一种确立。诚信,是我国所固有的一种优良传统,也是延续了几千年的一种民族美德,在中国儒家的思想体系里,是伦理道德内容中的一部分。

《现藏于台北故宫博物院》

现实真的是那么美好吗?小时候的价值观教育未能改变社会的现状,缺少契约精神的案例却比比皆是。

那么,契约真的要消失了吗?不尽然,在软件测试领域,我们又重新拾起了契约这把利器。

发展历程

接下来让我们把时间回溯到2011年初,回到老马的文章《集成契约测试》中来,回顾一下契约测试的起源和发展历程:

假设我们有这样一个场景:A团队负责开发API服务,B团队进行API调用消费服务。

为了保证API的正确性,我们会对外部系统的API进行测试(除非你100%相信外部系统永远正确和保持不变),这很可能就会导致一个问题,当外部系统并不那么稳定或者请求时间过长时,就会导致我们的测试效率很低,并且稳定性下降。比如当外部API挂掉导致测试失败时,你并不能完全确信是API功能被更而改导致的失败还是运行环境不稳定导致的请求失败。

最初,解决这个问题的方案是构建测试替身(Test Double),通过模拟外部API的响应行为来增强测试的稳定性和反应速度。实现手段是在测试环境中搭建一个模拟服务环境,通过设定一些请求参数来返回不同的响应内容,然后再被内部系统调用,来保证调用端的正确性。构建模拟环境时我们可以使用几种不同的测试手段,如Dummy,Fake,Stubs,Spies,Mocks等。可是,问题又来了,如果使用测试替身那如何能保证外部系统API变化时得到及时的响应,换句话说,当内部系统测试都通过的通过时,如何能保证真正的外部API没有变化?

一个比较简单的方式是部分测试使用测试替身,另外一部分测试定期调用真实的外部API,这样既保证了测试的运行效率、调用端的准确性,又能确保当真实外部系统API改变时能得到反馈。

是不是到这里就皆大欢喜了呢?

如果剧情到这里就结束的话,未免太过俗套。这个方案最大的缺陷在于API的反应速度,真实外部API的反馈周期过长,如果减少真实API测试间隔时间就又会回到文章最开始的两难境地。

那么如何解决这个问题呢?先来让我们剖析一下前面几种解决方案的共通点。

在上面的场景中,我们都是已知外部API功能来编写相应的功能测试,并且使用直接调用外部API的方式来达到验证测试的目的,这样就不可避免的带来两个问题:

第一,服务消费方对服务提供方API的更改是通过对API的测试来感知的。

第二,直接依赖于真实API的测试效果受限于API的稳定性和反映速度。

解决方式首先是依赖关系的解耦,去掉直接对外部API的依赖,而是内部和外部系统都依赖于一个双方共同认可的约定—“契约”,并且约定内容的变化会被及时感知;其次,将系统之间的集成测试,转换为由契约生成的单元测试,例如通过契约描述的内容,构建测试替身。这样,依赖契约的测试效率优于集成测试,同时契约替代外部API成为信息变更的载体。

对于契约来讲,行业内比较成熟的解决方案是基于YAML标记语言的Swagger Specification(OpenAPI Specification),或者是基于JSON格式的Pact Specification

通常的做法是API的提供者使用“契约”的形式,将功能发布在公共平台,给调用方进行说明和参考,这里我们可以暂时称之为Provider-Driven-Contract。这种做法的潜在问题是,功能提供方的API返回内容是否都满足所有API调用者的需求不得而知。所以,针对这个问题,依赖关系再一次反转,契约测试就摇身一变成为了Consumer-Driven-Contract test(CDCT), 通过给API提供方提供契约的形式,来完成功能的实现。

难道CDCT成为了问题终结者吗?请听后面分解。

注: 契约测试其中一个的典型应用场景是内外部系统之间的测试,另一个典型的例子是前后端分离后的API测试,这里不做过多展开。

契约测试的维度

1.测试覆盖范围对比(纵向)

单元测试:对软件中的基本组成单位的测试,大多数是方法函数的测试,运行速度快。

契约测试:对服务之间的功能进行的测试,运行速度基本与单元测试相同。

E2E 测试:对系统前后端或者不同系统之间的集成测试,大多通过模拟UI操作的方式实现,运行速度三者之中最慢。

2.测试效率对比(横向)

环境依赖:

  • 单元测试:程序集
  • 契约测试:程序集、依赖契约文件、虚拟路由服务
  • 端到端测试:程序集、真实路由服务、前端UI
  • 运行速度: 单元测试 > 契约测试 > 端到端测试

Pact官方给出的几个场景:

适用场景:

  • 团队能把控开发过程中的Consumer和Provider端
  • 适合Consumer驱动开发的场景
  • 对于每个独立的Consumer端,Provider端都能管理好需求。

不适用的场景:

  • 公共API或者是OAuth授权服务
  • Provider端和Consumer端没有良好的沟通渠道
  • 针对性能的测试
  • Provider端的功能性测试(Pact只测试内容和请求格式)
  • 对于不同输入有相同的输出,并未达到验证的目的
  • 当前测试输入需要依赖之前测试返回的结果

以上对比说明契约测试所要解决的问题是替代系统之间的集成测试,通过契约和单元测试的方式加速系统运行。同时也说明契约测试存在一些不适用的场景,要依据使用场景区别对待。契约测试没有取代单元测试以及E2E测试。

契约测试与CD的整合

最开始,我们的pipeline是这样的,单元测试是独立的测试,当通过单元测试后运行集成测试。此时集成测试成为了系统瓶颈,而且一旦集成测试失败,就必须被迅速修复,其他pipeline只能等待其修复,否则任何新的变更都会测试失败。

一个解决办法是将集成测试分散在每个pipeline上,每次集成测试运行的版本是当前的最新代码和其他系统的上一次通过版本之间的测试。这样解决了测试的独立性以及不会阻碍其他pipeline测试的效果,然后将通过测试的不同系统的package按照版本保存。但是这样一来,集成测试的缺点就更为明显提现出来,第一是系统部署时间长,每次集成测试需要运行同样的测试在不同pipeline上,增加了测试成本和反馈周期。

​​ ​​ 接下来,我们使用契约测试替代集成测试。这样有几点好处不仅解决了独立测试的目的,同时解决了集成测试慢和部署时间长等问题。

为了保证契约测试的正确性,契约文件由Consumer端生成,然后Provider端来实现API,我们使用CDCT来改造我们的pipeline。

我们先假设B系统希望A系统提供新功能,如果按照图中黄色步骤来提交的话,则会测试失败,原因在于此时,契约文件是最新的B-A.consumer.1.1.pact与之对应A-B.provider.1.0.jar不是最新的,所以测试失败。

按照图中步骤2运行,当提交A的pipeline时,当前版本的A已经升级到1.1,而契约文件还是1.0版本,没有break测试的情况下,最终将A-B.provider.1.1.jar提交到服务器上。​

然后按照图中步骤3运行,A-B.provider.1.1.jar和B-A.consumer.1.1.pact完美契合,最终又将B-A.consumer.1.1.pact提交到服务器。所以,改成CDCT之后,虽然产生了一定的提交顺序依赖,但是带来的更多的好处是确保契约文件的产生是调用端提出,并且保证当前最新,确保系统的正确性。

喜欢思考的同学不难发现,CDCT存在自身的缺陷,一个简单的例子是当B存在一个已有的契约约束A的一个功能,当B需要A更新其API时,是先提交B的契约测试,还是更改A的功能到最新版本?其实二者都不可行。

解决办法万变不离其宗,就是大家熟悉的不能再熟悉的重构心法,由王建总结的十六字箴言:​

我们分五步来完成API的更新:

  1. Provider端提交一个新的API来保证新功能,同时旧的API功能不变,提交并通过测试。
  2. 将Consumer端API的调用指向Provider端的新API,并更新契约文件以约束新功能。
  3. 将Provider端旧API同步更新为新API,提交并通过测试。
  4. 将Consumer端指回旧有API,其他保持不变。
  5. 将Provider端临时过渡的新API删除。

至此,我们解决了API更新时如何保证契约测试的提交顺序,如果是删除API,则直接删除Consumer端的契约测试即可。

需要思考的问题:

1.如果并行测试的话,谁先提交成功的版本,另外一个测试是否要重新运行?

设想,当两个并行pipeline A和B,同时运行时,A中跑的是A1.1和B1.0,B中跑的是B1.1和A1.0的测试,假如双方均能通过各自的测试,但是新版本不兼容(A1.1和B1.1测试失败),双方都将各自的新版本保留,这样就造成了存在相互不兼容的两个版本。目前解决方案是,人为制造一个“瓶颈”,保证同时只有一个契约测试在运行,保存的只有一个版本。

2.契约测试可维护性如何?

构建契约测试类似于单元测试,并且在Pact的框架下十分方便维护。但是,测试框架本身还有一些问题,诸如,大小写敏感,空值验证,只有一份契约文件,契约测试分组等。

(以上是基于pact 1.0的实践,pact2.0使用了正则表达式以及TypeMatching等机制解决了验证“具体”值的问题,更多详细内容请关注pact官方文档

结语

契约测试不是银弹,它不是替代E2E测试的终结者,更不是单元测试的升级换代,它更偏向于服务和服务之间的API测试,通过解耦服务依赖关系和单元测试来加快测试的运行效率。


更多精彩洞见,请关注微信公众号思特沃克

Share