测试左移是多年来测试行业的热门话题,在实际的践行中容易停留在“意识流”层面,仅仅是鼓励测试人员应该“主动做什么”,然而在业务压力大的常态下,被鼓励的尝试往往无疾而终。只有基于敏捷理念的理解,对研发生命周期的各个环节进行质量内建实践,才能把测试左移落实成好习惯,形成好流程,最终内化为敏捷团队的本能。
具体而言,测试左移,可以移动到需求澄清阶段,也可以移动到开发设计、编码和开发自测阶段。
而测试右看,是指当研发阶段的测试活动结束,产品进入发布上线阶段时,测试人员依然不能放松对质量数据和用户反馈的敏锐度,持续汲取下个迭代如何改进的反馈,形成滚动提升的飞轮。
本章将基于多年来的测试团队实践,分享在测试左移与右看活动中的推荐做法和有效经验,它们也是敏捷理念在测试活动中的落实,应在整个软件生命周期中持续性测试。
敏捷测试的本质是尽早测试,频繁测试,推动质量从源头内建。
而产品研发的源头,自然是需求产生及澄清阶段。精益需求的产生过程,就是测试左移最早可以发力的地方。
如果我们忽视需求阶段的测试左移活动,仅依靠软件工程层面的效能提升,始终会存在部分本质矛盾难以解决的情况。需求质量难以提升,很容易给技术团队带来频繁的返工和浪费。测试左移到需求的本质,就是从一开始尽量提高需求的可测性。
基于敏捷知识,我们先从精益需求的产生过程开始简要介绍。
一个软件产品需求的产生过程可以简单分为几个阶段,最终形成价值验证的闭环,如图3-1所示。
图3-1 精益需求的产生过程
业务需求 :确定产品的愿景、商业机会和核心价值(包含产品定位的差异化策略等),并确定目标群体,以此为蓝图制定本年度的商业发展目标,包含量化指标。
用户需求 :通过多种调查方式,如用户访谈、用户画像、用户调查问卷等,完成相关的定性/定量分析,挖掘出真正需要满足的用户诉求,即定义好产品的“问题域”。在此阶段可以将梳理完成的用户需求写成BRD(商业需求文档)。
产品设计方案 :在产品核心目标和定位的基础上,根据用户的本质诉求,形成完整的产品设计创意思路,最终给出可落地的产品设计方案,即梳理出产品的“解决域”。所谓可落地就是成本、时间、技术能力等限制条件都可以满足。这个阶段就可以开始输出PRD(产品需求文档)了。
功能需求 :根据产品设计方案,对产品能力需求进行梳理和优先级排序,整理出具体的需求描述,然后进一步识别/拆解为可开发的用户故事。
完成了上述的需求定义过程后,产品负责人组织需求评审会议,与技术团队以及其他项目干系人澄清产品方案,分享需求背景知识、需求定义和优先级。团队估算工作量,确认交付计划(包括重要发布计划和短期迭代计划)。
以上就是常见的需求产生及澄清过程,其间并非只由产品人员唱独角戏。在这些阶段中可以进行上一章介绍的多种敏捷测试实践活动。我们可以从下面几个方面进行质量把关,并输出专业意见,帮助产品经理和特性团队在进入开发环节之前提升需求质量。
1)明确需求价值。
2)完善用户画像和用户故事场景。
3)需求评审前给出验收测试点,帮助团队建立需求验收标准。
4)迭代需求拆解及合理估算任务,将测试任务纳入估算。
5)需求评审的质量把关,并明确DoR纪律。
首先,需要从业务方或产品经理处获得背景知识:为什么我们要提出这个需求?
第一,不提这个需求有什么损失?用户对我们这个需求有多期待?有没有具体反馈声音可以让我们学习?这对于测试场景的思考有极大好处。
第二,这个需求对公司有什么好处?是能提高满意度口碑,还是能提高收入?有利于我们未来盈利吗?新需求是否匹配产品的“调性”(定位),它是否有利于产品长期目标的达成?
能提高用户口碑或者提高利润的功能,自然是我们着力要保障的高优先级需求。
知道了业务价值以及成功的方向是什么,就能更充分地调动项目参与工程师的积极性。
其次,如何客观度量产品特性上线后带来了预期的价值?
虽然产品负责人对产品设计的价值(或商业变现目标)负责,但是产品价值体现在具体指标上,与用户场景息息相关。测试人员知道了商业上的度量指标定义和目标,就能更加关注要验收的核心场景。
另外,对于预期价值的思考及信息同步,也给了产品负责人以终为始的压力。产品需求绝不是越多越好,甚至有可能新功能上线越多,用户流失越快。把产品预期价值和背后的逻辑“晾晒”给技术团队看,既可以推动产品设计人员在设计时更加深思熟虑,又可以获得技术人员宝贵的早期意见输入。
再次,多挖掘与本产品相关的竞品信息和行业信息。
看竞品。 本产品的竞争对手为用户提供了哪些相似能力的解决方案?它们和本产品的差异是什么?实现方案有什么不同(哪个感觉更靠谱)?测试人员从中思考什么场景、什么指标可以用来做竞品对比。
看行业(本领域) 。本产品所在的细分领域,有什么规范/默认潜规则是本产品(需求)应该顾忌的?本领域是否有约定俗成的产品形态/交互风格,让用户早已养成习惯?这背后有什么博弈故事吗?理解约定俗成的法律、规范、强大习惯,可以让测试断言(是否有效缺陷、严重程度如何)更有底气,降低争论成本。
最后,当需求功能上线一段时间后,敏捷特性团队通常应该复盘上线的结果,确认具体商业价值指标是否达到预期,产品设计方案是否达到预期,还可以针对上线的具体特性功能,观察用户使用健康度(通过数据埋点)是否达到设计预期。
如果没有达到预期,产品团队要思考背后缺失了什么,以此来调整后面的设计方案和需求安排。
测试人员同产品经理一道,梳理用户画像并给出自己的看法,再根据目标用户的特征和视角,针对性地调整测试优先级和覆盖场景。
目标用户是从哪些维度来划分的?
一是从人口学特征划分,包括年龄、性别、地域、人体特征(如左撇子、手的大小、视力情况等)。
二是从使用习惯和经验划分,如新用户和老用户,强目的型用户(专找秒杀,或用完即走)和漫游型用户(随便看看)。从中我们可以总结出用户的痛点及他们对产品的期待。
三是从文化背景/社会背景划分,识别用户的特征,如城市白领、小镇居民、农村居民等。对于测试人员不熟悉的社会文化背景,比如海外市场产品,有必要认真学习当地社会文化知识,甚至出差去该国家走访,体验典型用户所处的生活氛围。
四是从平台角度划分,是公司外部用户还是公司内部用户(如管理员)。
理解了划分的主要用户类型,我们可以在脑海里尝试给每种类型创造一个生动的典型人物,起一个名字,如电商产品的用户——张小婷,想象她具备上述哪一种个性特征,如果她给我们产品的各个功能进行满意度打分,会打几分,标准是什么,她会用什么关键词来表达情绪。
当然,我们也可以从客服“用户之声”详细原声访谈中,或者从产品经理做用户调研的定性分析和定量分析中,寻找生动的典型用户形象、使用习惯和评价尺度。
梳理产品的主要用户故事场景
主要用户故事场景即 测试应优先关注的覆盖场景 。
随着梳理出来的用户故事越来越多,可以按照一定的时间先后顺序(横向)和必要程度(纵向)进行排列梳理,形成一张用户故事地图。产品负责人也会根据必要程度把梳理出来的用户故事分批纳入不同的发布版本计划。如图3-2所示。
借助创建用户故事地图的头脑风暴活动,我们可以更加明晰产品需求的价值及发生场景。具体可以从以下3点进行梳理和交流。
1) 用户类型分析 :主要有哪几类典型用户,按什么属性清晰区分?每一类用户使用产品(需求)的主要场景(差异化场景)在哪里?该类用户是如何在使用中获得满足感的(实现想要的价值)?
2)这几类用户的占比如何?行为习惯和关注点有什么差异?是否有调研数据支撑这个结论?这会成为我们判断场景优先级的参考。
3)关注用户故事地图中的“风险区域”。某些用户功能面临多样的分支路径,需要进一步拆解为多个子场景;也有一些场景的预期响应结果难以判断,需要进一步剖析。我们从地图中会发现,这些有待挖掘的“麻烦”通常集中在地图中的特定功能区域,这个区域既是产品设计的难点,也是质量验收的难点。
图3-2 基于用户故事地图的场景梳理
以“ 手机管家App产品” 为例,最早的产品主打功能是安全,防范手机木马病毒,但在实际运营和对用户行为的洞察中发现传统安全的场景占比很低,而反骚扰、隐私保护等“泛安全”的需求更为迫切。于是产品的需求重心向泛安全演化,相应的测试体系内容也发生了很大变化,从以木马病毒的识别为高优先级转换为以骚扰拦截效果、隐私漏洞等为高优先级。
随着产品用户进一步扩展,为了突破价值瓶颈,手机管家的重心变为更高频的用户需求——手机空间管理(瘦身功能),因为空间占用越来越大且大容量手机价格昂贵,相关体验和精细化需求持续升级。测试策略和自动化建设的重心自然也发生了变换,安全类功能变成以稳定运营为主的模块,而团队在瘦身效果评测、微信等空间占用大户的专项清理等场景投入了更多的测试精力,以确保用户价值——“清理要快、空间释放足够大、重要信息不误删”这3项指标达到设计预期。
在产品经理组织需求评审会之前,是否可以对需求定义的概念进行“逻辑测试”?
我们可以提前和产品经理沟通需求规格文档,提出修改意见,或者抛出有针对性的验收测试点请对方确认,如图3-3所示。
在需求评审会议上,我们也许可以一边看着需求规格说明,一边看着需求对应的验收测试点,甚至列出包括历史上真实发生过的关联缺陷!这个时候,开发人员可能还没有开始思考如何实现。如图3-4所示是需求和测试点二合一表格示范,以方便团队在需求评审时同步核对质量风险和验收测试点,提高评审效率。
图3-3 测试人员和产品经理在特性需求评审前的讨论
图3-4 需求和测试点二合一表格示范
这种创新措施的好处就是,开发人员把测试人员要验证的关键场景早早地记在脑里,再交付时几乎不会出现对于测试人员而言很低级的质量问题。
需要说明的是,测试人员提前梳理的这些测试点,可以经过产品经理确认后成为用户验收测试用例(UAT),也可以细化为(方便开发人员自测的)普通验收用例(AT)。
第2章提到过,敏捷研发团队针对需求评审完成条件可以设置准入门槛,定义为DoR,这也是团队共同遵守的纪律。DoR中通常会要求用户故事的“验收测试用例”必须由团队确认完成。一旦验收测试用例成为团队各个环节的“交付共同语言”,将极大地推动各个角色从一开始就重视质量,并且清楚自己的工作是如何对齐质量要求的,避免不同角色对于需求质量的理解差异太大。图3-5展示了在迭代的各个环节验收测试用例作为共同语言贯穿全流程。
图3-5 验收测试用例贯穿迭代的各个环节
按照敏捷理论,迭代计划会议要对本迭代的需求进行合理拆解、工作量估算,同时结合PO决策的需求优先级,确认本迭代要完成的用户故事有哪些。从表面看来,这个迭代计划会议不是测试人员主导,但是计划制定与测试人员安排的合理性密切相关。
如果需求或用户故事的颗粒度太大,将不利于迭代内的高质量交付,这是最常见的项目风险情形。我经常见到测试人员排期的困境,就是由于需求过大,导致测试设计及场景讨论花了太多时间,交付速度很慢。如果一个用户故事的开发周期在2~3人天内,它的测试验收效率是非常高的,可以当天完成测试任务并提交反馈,避免开发人员等待时间过长。
因此,敏捷特性团队应该对偏大的用户故事进行拆解,以便在本迭代内可以排期完成。作为测试人员角色一定要关注这个拆解的“可测性”,拆解后的用户故事应该可以完整验收,否则就违背了敏捷迭代的原则。如图3-6所示,我们应该采用图中第二行这种交付方式,即每个迭代完成一个让用户可以使用的“增量”产品。
图3-6 每个迭代都交付可用的产品
在测试工作量的预估上,我们认为“任务”是最小的工作量估算层次,一个用户故事的研发由多个任务组成,其中包括测试任务。建议测试任务的划分不要太粗,单个任务的完成时间不超过1人天,这样有利于团队找到测试效率可以提升的地方,同理,不同测试人员的任务也建议分开估算。
测试任务的独占周期太长,也会影响迭代需求的完成目标,我们有必要具体看看测试范围和优先级,找到合理的覆盖策略,保障核心功能用例的验收。
实际迭代排期中经常出现产品经理把新的需求紧急插入本迭代的场景,这会让开发人员和测试人员很不满。针对紧急插入需求,应该如何正确看待?
从敏捷价值观而言,我们拥抱变化。没有必要强制需求排期计划不能变更,哪怕是在本迭代这么短的时间内。但是我们有必要集体确认:新排入的需求优先级如何?它和本迭代中计划完成的其他需求对比,优先级是高还是低?如果它的优先级比本迭代的某个需求高,在迭代剩余工作量能完成的情况下,可以替换当前正在做的需求。
简而言之,针对紧急需求插入,不能只做加法,而是有加有减,根据优先级拥抱变化,根据团队速率替换一定大小的排期需求。因此,我们也要检查产品待办列表中的需求优先级是不是有严格的唯一排序,这很重要,有进就会有出。
存在一种可能性,即有的产品需求永远都无法排期开发上线,因为它的优先级永远比不过后面的新需求。这也符合敏捷设计的价值观,即适时设计。当前重要的产品想法,可能到了后期便不再重要了。
首先要明确,需求的设计质量并不是只由产品经理负责,特性团队的每个成员都应该对需求设计的高质量负责。很难有人能够通过市场、用户和技术等方面的全盘思考,拿出一个高品质的产品设计方案。团队需要群策群力,帮助产品经理快速提升需求设计的质量水平,并且定义达到足够水平的文档质量标准。
敏捷团队不追求文档的详尽,而是要求定义清楚边界和风险。对于具体纳入哪些“必填内容”,可以由一线团队根据自己的业务特性和规模来定制,例如针对初期上市产品,需求评审更关注主打什么功能,而不是缺失什么功能。
以下是我推荐的需求文档质量把关项:
1)需求的上线背景和商业目标是否明确?需求的来源和交付日期是否明确?
2)如何评估本需求带来的商业价值?上线应关注的产品健康度指标有哪些,期待值范围是多少?
3)是否有针对本需求的市场分析和竞品分析(可选)?如果需求规格复杂,需要提供业务逻辑图。
4)本需求在哪个主体上实现,它的上下游是谁?本需求对上下游主体有什么影响,交互逻辑是什么?本需求的成功上线依赖哪些服务,具体依赖关系如何?
5)本需求是否涉及性能变化、稳定性风险或者资金安全风险?如果涉及,请给出详细分析。(可请开发人员给出。)
6)所有需求的优先级是否明确且唯一?
7)本需求的上线策略是怎样的?
最后,除了上文提到的把“完成验收测试用例”这一条纪律纳入DoR,我们还可以把其他有利于需求质量提升的好纪律都纳入DoR,让团队共同为需求的精益化负责。只有DoR全部完成,才意味着需求评审阶段全面完成,可以进入开发设计环节。图3-7是一个团队设计的完整DoR例子。
图3-7 完整DoR的例子
“磨刀不误砍柴工”,澄清需求过程中多一些思考碰撞,未来构建产品质量的成本就会低很多倍。关于具体可以从哪些角度详细挖掘需求的可测性,请读者参考第8章的相关内容。
众所周知,测试活动越早进行,在早期发现缺陷的数量就越多,而且单个缺陷的修复成本也会越低。如果缺陷在接近发布前被发现,修复的总成本要提高一个数量级,如果缺陷上线后才被发现,带来的损失可能再高一个数量级,达到令人吃惊的程度。
根据Capers Jones在《全球软件生产力和质量度量分析报告》中给出的图表数据,假设在编码过程中修复一个缺陷的成本是1,那么在单元测试中修复一个缺陷的成本是4,而功能测试和系统测试的单个缺陷的修复成本分别是10和40。如果遗漏到线上,修复成本将飙升到640!
通常在开发阶段,开发人员做的事情是完成开发设计文档、编码、代码评审和开发自测等工作。与此同时,测试人员的常规活动是测试策略准备、测试用例设计、用例评审和自动化测试相关准备等。
本节提到的测试左移,是指测试人员除了要学习开发人员提供的设计技术文档(用作测试设计的参考)以外,还要积极参与和开发人员相关的如下重要活动,更早地暴露问题,减轻而非加重开发人员的负担。
1)参与开发设计评审。
2)推动测试驱动开发(Test Driven Development,TDD)与单元测试门禁。
3)参与代码评审活动。
4)落实代码规范。
5)完成桌面评审,即完成验收测试。
6)持续测试建设,完善测试分层建设。
测试人员的目的从发现缺陷变成预防缺陷,这会导致他与开发人员协作关系的重大变化。
在传统研发团队,软件的开发设计包含概要设计和详细设计,测试人员并不被鼓励参与开发设计评审。实际上这个评审活动有利于测试人员获得重要的业务架构、功能和非功能的实现信息,对于测试策略和用例设计可能会大有启发,也会为精准测试提供关键信息。
测试人员参与开发设计评审,应优先关注软件的整体架构、分层模块和底层模块的视图,追问设计方案的选型原因、资源限制场景、可靠性保障机制、安全处理机制等,借此埋下“如何基于设计风险做测试设计”的种子,降低测试探测的盲目性。开发人员在设计讨论中的争论,也许提示了潜在的高风险信息。
从参与设计评审开始,测试人员和开发人员就能在对等信息的基础上进行质量问题的本质探讨。
行业中有一种观点,认为如果测试人员过于熟悉开发的实现思路,就会站在理解开发人员的角度来测试,不会想尽办法找到破坏路径。我不这么认为,只要刻意训练,测试人员就可以充分利用白盒信息和黑盒观察的各自优势,快速切换成不同的测试角色(开发人员或普通用户)来高效地挖掘问题。
TDD常见的类型有两种,即UTDD(Unit Test Driven Development,单元测试驱动开发)和ATDD(Acceptance Test Driven Development,验收测试驱动开发)。两者的差异如下。
UTDD是测试用例在先、编码在后的开发实践方式,属于单元测试的层次。开发人员通过不断让单元测试通过,提升对代码的信心,再持续优化和重构代码,保持用例通过,这样可以尽可能地降低重构的风险,让开发人员可以更放心地进行快速重构,提高迭代效率。UTDD弥合了开发实现和单元测试的分界线,将传统开发过程倒转过来,借助测试代码增量地驱动设计。
ATDD则是在业务层面的实践,基于前面介绍的验收测试用例,驱动开发面向客户需求进行场景设计和代码实现。
专职的测试人员直接介入UTDD活动是比较困难的,但这并不意味着测试人员不能推动UTDD的优秀实践。我们可以借助持续集成流水线,以及团队对于单元测试质量的重视,把单元测试门禁作为持续提升代码质量的基础,只有通过门禁才能进入下一轮研发活动,从编码源头内建好质量。具体行动步骤推荐如下。
1)在团队中普及UTDD知识和实践方法,让大家理解并遵守单元测试编写的基本原则。
❑单元测试要求全自动化运行,速度要足够快(毫秒级)。
❑单元测试要独立。用例不依赖外部资源(如外部数据、接口和网络等),用例之间也不互相依赖。
❑单元测试可重复测试,稳定性极高。
❑单元测试集要保障较高的覆盖率,及时更新用例以覆盖最新代码。
2)基于团队评估讨论,可以设置单元测试通过的标准,如运行耗时上限、测试集通过率、代码覆盖率等。
3)在研发测试流程平台(或DevOps平台)上,接入对应编程语言的单元测试框架,将单元测试关键指标显示到实时质量看板上。
4)针对未达标的单元测试,查看详细报告并进行优化。常见的质量问题有耗时太长、增量覆盖率或全量覆盖率太低、缺少正确完整的断言检查等。整改未达标的单元测试,不能进入下一步的提测环节。
切记单元测试覆盖的目标是所有重要的代码路径,但不是和具体实现代码过于紧密的耦合,以避免内部代码一旦改变,单元测试就失败。
此外,不要为了提升被测代码覆盖率而忽略了重要的断言检查,包括对返回值的检查、对方法参数的检查、对异常值的检查等。高质量的断言检查才能让单元测试成为出色的质量防护网,不惧代码的频繁更新。
代码评审(Code Review,以下简称CR)通常是由开发人员进行的。测试人员参与CR,也能获得不小的收益,不仅能学习到开发人员实现软件的具体逻辑,也能快速寻找代码质量风险,尽快拦截问题。
长期参与CR,有利于工程师的快速成长,更有利于团队工程能力的协同。拥有良好CR文化的技术团队,也就拥有了尽早识别缺陷的能力,拥有了自觉完善代码的主动心态。
为了保障CR的顺利、高效进行,整个团队需要建立评审原则,包括:
1)确保每次CR只做一件事,即单一职责原则。重点放在业务逻辑检查上,看实现方案是否充分。
2)尽早评审,多次评审,而不是在快发布时才集中评审。
3)评审前先借助扫描工具查漏补缺,而不是单纯依靠人工检查基础错误。
4)为评审者提供详细信息。
5)要求评审人员做到及时响应,谦虚,不追求代码完美,指明必需的解决项,多多鼓励,等等。
测试人员参与CR时,可以特别关注软件的设计意图、可测性,以及在性能、安全、稳定性等方面的设计缺失,并思考可以进行缺陷探索的场景。当然,测试人员如果是业务整体架构和业务设计逻辑的精通者,则更能在CR中看到具体函数没有考虑到的上下游集成风险。
为了提高找风险的效率,测试人员基于现有缺陷特征分析的评审效率可能更高。我们可以从当前主要缺陷的根因分类来提炼CR的观察角度,也可以借助静态代码扫描工具的支持,批量化发现问题。举例如下。
1)App崩溃问题很多是因为空指针异常,那测试人员做CR就会特别关注对象的初始化,任何一个对象在使用前都要做判空处理。
2)不少缺陷的上报都是因为边界问题,做CR时会重点评审数组和列表的边界,判断是否有越界情况。同时,对于各种不正常的输入,判断代码是否做了完备性检查,并给予合理的异常提示。
3)针对应用的内存泄漏这个测试重点项,我们会分析出常见的内存泄漏原因以及代码实现中的错误表现。按这些反例提炼评审关注点,比如:对象如果注册了实践回调,是否在合理的地方进行了反注册;缓存对象、图片资源、各种网络连接、文件I/O等最终是否正确关闭。
4)专业的静态代码扫描工具也可以提供典型代码问题的分类定义和推荐解决方法,结合起来学习效果更佳。
最后,为了让代码评审流程规范化和更高效,也可以在研发管理平台上即时发起在线评审,多人的评审结论满足基本门槛后,平台才允许把代码提交入主干。
不少大公司会制定代码规范(Coding Standard),包括质量层面、风格层面和安全层面。测试人员针对代码规范往往可以做一些较高收益的尝试:协助制定适宜的代码规范,并积极推动激励制度落地,形成开发习惯。这相当于用很低的成本把很多潜在风险拦截在初期开发阶段,其性价比高于开发单元测试。
围绕代码规范,质量人员可以做以下三类动作:
❑推动代码规范的文档化和宣导。大公司的代码规范文档往往很容易获取,但是细则繁多,对开发人员提出了较高的要求,测试人员可以根据团队专业成熟度以及常见缺陷风险,选取其中的子集作为本团队的规范,在执行成本和风险拦截中取得平衡。
❑将规范检查纳入流程管控或者工具审计中。与开发人员就代码规范达成一致,在日常代码自动扫描中要明确告警规则,确保开发负责人即时响应处理,不允许随便取消告警规则。
❑同时,在引入静态代码检查工具阶段,测试人员也会参与,货比三家,务必在价格、质量/安全风险检出率、误报率、修复提示水平、售后技术指导等多个要素上推荐出更佳的开源或商业工具。图3-8是我们在2017年针对代码扫描工具SonarQube和Pinpoint的评测结果。
图3-8 SonarQube和Pinpoint(源伞)扫描工具的评测结果
❑作为中立方输出 代码规范专项审查报告 。代码规范的分类多样,我的经验是可以将代码规范细分为排版规范、注释规范、命名规范和编码规范四类,规范强度可以是“建议”或者“原则”。测试人员可以借助扫描工具和人工核查,针对特定违规现象做审计,输出分析改进专题,这种聚焦曝光和集中改进的效果往往让人印象深刻,泛泛而谈的审计报告则很容易失去可持续的抓手。
❑比如我曾带团队陆续输出的几期专题报告——App代码扫描专题、代码注释规范专题、冗余代码专题、圈复杂度分析专题等,充分利用多种扫描工具,配合人工核实问题有效性,聚焦清理一类问题,因此开发人员解决问题的速度很快,让团队也很有成就感。
开发人员完成编码和调试后,如果马上部署测试环境开始进行端到端的验收,那么就进入高成本的测试活动。当测试人员发现了可能的缺陷,找开发人员进行确认时,开发人员可能已经在开发另一个需求了,必然产生更多的任务切换和沟通的成本。
如果开发人员完成编码和调试后进入桌面评审活动,比要求开发人员承诺“自测”的方式更有利于提高开发质量。有些公司也称之为Showcase。该活动只需要在开发人员的本地环境验证(测试数据由开发人员自行准备),组织特性团队和干系人的集体会议,由技术人员进行功能演示。通常在演示中会执行验收测试用例。如果验收测试用例不通过,则可以返回让开发人员进行修复,未来再安排新一轮桌面评审。如果验收测试没有发现严重问题,可以进入系统测试阶段。
这个质量评审活动体现了敏捷宣言的核心实践: 个体的交互及合作比固定流程更重要 。
基于本人的实际感受,因为桌面评审形式公开直接,开发人员会进行充分的测试准备和确认。参与桌面评审的人员如果原本不太熟悉业务细节,通过参与验收展示的全流程,会对业务交互逻辑有非常深入的理解。
持续测试(Continuous Test,CT),也有公司称为每日测试(Daily Test),就是每天都有新版本生成并完成相应的测试活动,绝大部分测试都是自动化测试,但是也可以推送新生成的安装包到成员的终端上进行人工内部探索测试(dogfood)。尽可能在当天就发现是否有基本功能被新代码破坏掉,以缩短解决问题的闭环,并让大团队对新代码提交保持信心,这样的实践契合“频繁测试”“集体对质量负责”的敏捷原则。
为了保障持续测试顺利进行,团队首先要确保持续构建的成功率,必要时督促开发人员立刻处理,建立对健康构建的重视态度比完善工具更重要。
测试人员还需要关注项目的构建效率,通常应控制在10min以内。在实践中发现,导致构建耗时太长的原因经常来自于测试,比如包含了远程服务(如数据库)。
持续测试实践的成效是,在后期的系统测试阶段中发现的问题数量大幅下降了。没错,在测试左移中,系统测试中发现的缺陷占比越少,越有可能是件好事。
测试人员除了可以参与验收标准和验收用例的评审外,还可以在开发人员完成单个需求(用户故事)自测后,马上开始针对性的验收测试(如果产品经理能先行做用户验收测试则更佳),快速反馈单个需求的质量情况(最好当天完成),降低迭代版本测试或系统测试的风险。反馈周期越短,开发人员修复的效率越高,而传统的等待版本提测模式会拉长开发人员的等待时间,加大切换任务的注意力耗费。
持续测试中的自动化测试是分层进行的,因为不同层次的自动化测试耗费的时间不同,修复成本不同。参考Ham Vocke的测试金字塔理论,自动化测试可以分为下面几个主要层次。
1)单元测试。3.2.2节已有介绍,这里不再赘述。
2)集成测试。在很多公司,集成测试被称为联调测试,通常由开发人员负责,但是测试人员也可以共同建设。
集成测试可以分为狭义集成测试和广义集成测试。狭义集成测试聚焦于被测对象的服务边界,触发本对象和外部(另一个服务,如数据库或文件系统)的集成动作。而广义集成测试则是通过网络和外部服务进行集成,但是速度更慢,测试更脆弱。依托测试环境稳定的基础设施服务,集成测试通常按照从小到大的顺序联调,逐步提高服务的可用性。
从敏捷角度理解,联调意味着跨特性团队的协作,虽然难以避免,但属于成本的浪费,应该尽可能降低联调的投入和时间。如果参与联调的各方都有非常清晰、完备的接口定义,充分考虑了可能的错误场景,那么联调就可以在最短时间完成,甚至借助事先做好的自动化用例自动完成。
因此,在微服务产品中,契约测试(作为一种特殊的集成测试)流行开来,所有微服务的接口测试都根据定义好的接口契约,设计完整、稳定的测试用例套件,确保数据的生产者模块和消费者模块遵循契约。基于该套件的每天持续测试把关,研发团队便向自治团队迈出了一大步。
3)UI测试/端到端测试。注意,UI测试是端到端测试的一部分,即在交互界面上验证结果。端到端测试还有不少其他层面的验收标准,比如没有界面的功能、系统性能、安全性检查、日志正确性、交付规范的文档等。对于微服务架构的产品,需要有人面向整个系统、跨越多个服务来编写端到端测试用例。
这些自动化测试层次使用的测试框架各不相同,但持续集成平台都可以纳入,并行执行,根据团队的效能度量要求进行任务配置和结果治理。哪怕是不完美的自动化测试,只要能够频繁执行,也比很少执行的完美测试更有价值。
而前文提到的验收测试,与测试金字塔的各个层次是正交的,你可以依托单元测试来验收,也可以从接口验收,当然也可以在UI层验收。
如果一个功能验收可以同时在低层次和高层次自动化实现,那就应该保留低层次测试用例,而放弃高层次测试用例,以减少用例重复。但是,如果高层次的用例能够提高我们对于产品发布的信心,那就应该保留它。这也是我认为单元测试及集成测试不太可能完全替代端到端测试的原因。
完成端到端测试(也可以称为系统测试)阶段后,进入灰度发布或正式发布阶段。测试人员除了采集和分析缺陷外(具体会在第8章详细介绍),也需要抽出一定精力,持续进行高价值的质量保障活动,包括:
1)参与或组织可用性测试。
2)关注持续部署和发布。
3)压力演习与混沌工程。
4)服务质量监控。
5)用户行为埋点与用例优化。
与其全身而退(立刻投入下一个新版本的测试准备),不如花一些精力对当前发布版本多做一些高价值的质量活动,获得宝贵技能,再通过问题反思不足,验证测试策略的有效性,以便在下一个发布周期做得更好。
可用性测试,是指让一群有代表性的用户对待发布产品做典型的操作,产品经理或观察人员在一旁观察、聆听、记录,得出改进结论。
可用性测试来源于人因工程(Human Factor),又称工效学,是一门涉及多个领域的学科,包括心理学、人体健康、环境医学、工程学、工业设计等。ISO将可用性(Usability)定义为特定使用情景下,软件产品能够吸引用户并被用户理解、学习、使用的能力。
可用性测试在团队中通常由交互设计/用户调研组来组织,也可以由产品经理来组织,项目成员可以参与观察,测试人员亦可以从中获得意料之外的收获,学习真实用户是如何使用和认知产品的。
通常的可用性测试方法是找5~6个典型用户,花费30~50min,自由使用5~8个基本功能点。组织者会给一定的使用目的(不会很详细),但不会给具体的操作要求,激发用户自行使用。因此,用户其实并不是在刻意做测试。
在该过程中,观察者除了利用专业设备(如眼动仪)记录用户视线和行动步骤之外,还要查看使用过程中的交互步骤和视觉路线是否合理,离开主界面和主流程的时间是否异常,并搜集用户的优化建议。参考用户体验的模型,分析可用性有5个递进层次:能用、有用、易用、好用、爱用。
基于同样的思路,我们可以定制产品可用性调查问卷,特别适合参与灰度体验或者众包体验的用户来填写,问卷的核心是获取下面4个评价。
❑ 高参与 :能否完成既定目标,如工作需求,或满足娱乐需求。
❑ 低门槛 :学习曲线是否足够低,在多短时间内能掌握新功能。
❑ 高效率 :操作流程是否足够短,完成任务耗时是否足够短,导航是否快捷。
❑ 强稳定 :用户感受有安稳感,甚至满足感,下次使用产品时无须记忆,手到擒来。
完成可用性测试后,测试人员可以反思一下目前的测试策略、覆盖场景、验收条件是否已关注到用户容易不爽的地方,有什么改善的空间。
关于持续部署和发布,本节主要从3个方面展开介绍。
关注持续部署
DevOps时代的部署应该是持续进行的,这个过程高度自动化,为了做到这一点,配置部署的流水线需要能够快速反馈部署的问题,去除手动配置的成本和风险。我们可以在日常环境、预发环境和生产环境分别部署流水线,也就可以把相应的测试检查内容纳入部署流水线门禁中,真正做到测试右看。
为了提高部署的成功率,也就是提高交付效率,我们应该维护一个单一源的仓库,把测试脚本、属性文件、数据库概要、安装文件和第三方库放置在一起,即所有用来构建产品的东西都放到版本控制系统里,一旦其中某个对象发生变更,那么依赖它的所有对象都需要被重新构建。为了缩短部署和发布的耗时,测试人员可以关注应用的瘦身大小,把它作为专项改进目标。
灰度发布的测试活动
灰度发布就是导入一定比例的真实用户,由研发和产品团队观察用户使用的效果,如果没有异常再进行更大范围的灰度或者全量发布。灰度发布也可以只是获得关于新试验功能的结论(用户是否喜欢)。灰度发布可以在大规模推向用户之前,尽可能地发现并修正严重问题,同时降低发布压力,避免产品团队闭门造车,用低风险收集用户使用的反馈。
在灰度发布阶段,测试人员可以做哪些事?
首先,要明确自己在灰度发布阶段的测试(观测)目标。是观察性能问题、新版本体验问题,还是新旧功能的指标对比?注意关注已发布的机器是否有流量进来,避免表面上启动成功,实际上服务并没有生效的情况。
其次,参与灰度用户的选择策略,与产品经理及开发人员沟通灰度策略对于测试目标是否有代表性和准确性。比如:是否覆盖了重要的终端类型,是否覆盖了指定的角色特征,是否能针对特定场景采集测试结果。
最后,输出灰度测试报告,明确灰度测试发现的问题及严重性,给产品经理一定的改进意见,判断是否达到全量发布的质量标准,或者明确给出灰度“实验”的观测结论。
注意,如果针对灰度版本发起众包测试(第11章介绍),在搜集灰度反馈方面会有很高的效益。
主干开发和主干发布
参考硅谷Meta等大公司的经验,高度敏捷的研发团队应该追求单主干开发,其好处是巨大的,可以尽可能降低分支开发带来的版本冲突,以及长生命分支合入主干带来的高评审成本。但是想要实施单主干开发及发布,团队的各项质量及效率实践需要足够成熟,如可靠的持续构建门禁和代码审查门禁、TDD的良好习惯、高度的自动化测试覆盖率、每次提高变更的颗粒度足够小,以及未实现功能可以用开关统一控制。
当团队在单主干上进行日常开发和发布时,质量负责人可以联合团队确立合并代码的质量要求,包括前置要求(满足什么测试结果才能合入主干)和后置要求(合入代码后应该立刻启动保障型测试,确保红线标准不被破坏,一旦被破坏需要采用相应优先级的处理手段)。
此外,如果大量工程师在单主干提交了大量代码,那么逻辑如此复杂的产品在运行中可能会产生很多不稳定的测试结果,我们称之为Flaky Test。这类问题会降低团队持续交付的信心,而且小团队对此类问题的解决手段非常有限。开发和测试团队需要逐步建立治理Flaky Test的方案,包括消除各种外部依赖和用例依赖关系,做好并发处理和异步等待,尽可能减少随机行为,最后对本轮测试产生的Flaky Test进行标记并隔离处理。
对于复杂逻辑链条和海量用户的互联网业务,不论日常花多少精力做接口测试和性能测试,都不能保证真实用户场景的充分覆盖。尤其是分布式系统,一旦遇到大量用户的集中访问和各种操作,经常会暴露意想不到的问题,甚至会形成雪崩效应,造成核心服务瘫痪。因此,仅有敬畏之心是不够的。
测试团队作为质量保障的核心角色,可以和业务负责人及开发团队一起实施压力演习(或称现网演练),即针对特定的海量用户使用场景,在预发布环境实施,尽可能模拟真实活动的全过程,测试所处的环境数据库及配置,使用和线上一致的备份。施加压力的大小、时间、被压接口、变化过程,都是事先设计好的压测模型脚本,同时对复杂的后端服务链条做全链路监控。
压测前要做好充分准备,尽可能不影响真实的线上用户;压测后对性能数据问题做复盘分析,找到性能瓶颈,给出改进措施,优化下一次演练的方案。
为了避免压测产生的脏数据对真实用户的数据库产生影响,被测系统在保持线上环境的一致性的前提下,需要具备精准识别测试流量的能力(比如,依赖整个压测链路的流量标签),把产生的测试脏数据隔离保存到特定数据库里。
在压力演习中,有一类特殊的工程实践就是混沌工程,它已经成为独立的技术学科,最早源于奈飞公司的“混沌猴子”实践。混沌工程是一种生成新信息的实践,包括常见的故障注入手法。例如,引入特定的某类故障,针对被测系统的某个位置引入超时、错误响应、链路不可用等错误状态,在一段时间内观察系统如何处理,能否自动恢复,花费多长时间恢复,以及是否产生链式灾难反应。混沌工程也可以引入激增的流量、特殊的组合消息、激烈的资源竞争等。
实践混沌工程的推荐时机是MTTR(故障平均恢复时长)越来越长,故障根因不明的情况逐渐增多。正式实施前要和相关团队人员做好预告说明,明确实施动作和时长,给出相应的应对指南,将生产环境中受影响的范围控制到最小,按照现实世界中影响系统的事件发生概率来运行混沌实验。整个过程应该尽量自动化执行,具备可快速终止实验的能力以及实时观测各项指标的能力,能判断系统在混沌实验结束后是否回归稳定状态。
利用混沌工程主动制造“非稳态”,观察系统在压力下的行为,我们通常能发现一系列系统脆弱性问题。通过探索产生的影响,团队将逐步建立被测系统能够应对生产环境动荡状态的信心。我们鼓励测试人员和开发人员联合进行混沌工程实践,共同获得新的知识。
对于在线技术服务而言,任何一个时刻发生的严重问题都有可能引发用户的投诉,甚至成为影响公司品牌和收入的严重事故。与其被动地在线上质量事故突然发生后“灭火”和检讨,不如主动建立线上服务质量监控网,在第一时间觉察出质量风险并采取行动。
测试人员参与这类线上监控技术建设是有自身优势的。开发人员和运维人员更多是从应用接口、网络系统资源的层面进行底层监控,而测试人员可以利用已有的自动化脚本进行用户基础场景拨测,定时进行。
测试人员在进行质量监控时遇到的主要困惑,就是不清楚如何明确监控指标。监控指标不是越细越好,而是要能快速锁定突发问题出现在什么地方,还能通过指标大盘全面了解业务的健康程度,因此指标大盘一定要简洁直观,聚焦核心。
那么,阻碍服务监控产生预期效果的原因有哪些呢?除了本身技术能力不足,还有下列情况值得集体停下来改进:
❑破窗效应。监控出了问题没人关注,没有严格的响应处理机制。
❑告警海洋。告警频繁,数量大,重复,不及时,急需精简。告警监控指标太多,导致监控界面复杂。界面美观、可视化对于长期运营非常重要。
❑告警没有分级,也导致员工不清楚响应告警的时效纪律要求。
❑误报严重。如何降低告警的数量,是各大公司的共同痛点。大部分告警数量来自某些告警的持续性产生,因此我们是可以聚焦其相似性合并告警的。而基于AI的告警处理手段也是热门技术趋势。
❑定位问题根因的工具效率低,步骤多,准确性不足,严重拖长了MTTR。
❑服务质量监控系统和研发管理系统没有打通,没有形成线上缺陷单的一键跟进,不便于研发质量分析。
一旦研发团队发现了线上服务异常问题并处理妥当后,大家就可以一起进行复盘分析,思考故障恢复时间能否缩短,技术架构是否有不合理之处,能否完善监控看板的视图,能否强化日志定位工具的效率等。测试人员还可以从右看中获得有价值的输入,把获得的负面案例转化成性能场景用例或者接口测试用例,让未来的版本测试更完善。
测试用例的设计、自动化和执行占据了测试团队的巨大精力。如果从用户体验角度出发,这些用例对用户真实使用场景的代表性有多高?排除掉一些难以承担风险的“质量红线”用例,普通用例的执行优先级该怎么确定?
引入触达用例场景的“用户渗透率”作为挑选用例的权重,是很自然的思路。
例如:根据每一个交付价值的能力(场景),我们可以进行场景埋点,上线后统计用户使用该功能的渗透率,用深色表示高渗透率功能,用浅色表示低渗透率功能,这样就生成了测试策略的优先级提示,在有限的精力下,就可以多挖掘高用户渗透的核心能力相关测试用例,如图3-9所示(以Wi-Fi管家产品为例)。
图3-9 用户渗透率热力图(Wi-Fi管家产品)
我们在实验室难以重现的缺陷(包括性能问题),也是需要通过服务后台针对用户的监控,捕获同类缺陷的操作场景上下文、输入日志和性能数据,辅以直接与用户电话沟通,才有更多的机会重现问题,改善产品体验。
但需要指出的是,这对用户行为数据监控上报的方法也会带来不小的风险:
❑因为泄露用户隐私(电话、位置等)而违反隐私合规政策。
❑因为上报方案不合理导致流量异常增大,或者频繁上报导致耗电异常,可能会引发用户投诉或严重线上事故。
对应的优化技巧列举如下。
❑隐私合规:告知用户相关数据采集的必要性,让用户自主选择。
❑隐私数据加密。
❑流量控制,合并上报字段,压缩上报资源,设置为在Wi-Fi环境上传,延迟打包上报。
❑后台可以对是否上报、上报哪些做配置开关。
❑产品内嵌的上报SDK要提高质量,确保SDK的体积、响应性能、内存/CPU等对产品性能影响极低。
测试左移的本质是,既然越早进行质量内建活动,得到的收益越多,就把技术人员的一部分精力放在更早期的环节进行质量推动和把关,这样总的质量保障收益是更高的。
测试右看的本质是,既然验证发布效果是持续改进的动力,就在系统测试结束后,持续投入一定的精力,观察用户对质量的期待是否与认知相符,从而在未来的研发周期果断采取改进行动。
本章分别介绍了在需求、开发、发布阶段中,测试人员可以做哪些“左移后看”的具体敏捷实践。在需求阶段,测试人员要理解需求背景和目标价值,研究用户画像,梳理用户故事场景。如果能够在需求评审时给出验收测试点,并完善需求质量评审检查清单,就能够让开发人员在写代码前清楚“考点”,提高自测质量。在开发阶段,测试人员可以参与开发设计评审、TTD、代码评审、桌面评审和持续测试建设,落实代码规范,同时也能通过与开发人员合作获得软件内部的知识,及早揭示可疑之处。在部署和发布阶段,测试人员并不是早早转向下一个迭代工作,而是细心观察产品的可用性,监控关键服务质量和负面舆情,关注发布质量目标是否达成,及时干预品质口碑的风险,甚至可以根据用户行为数据对冗余用例集做优化。