这是鼎叔的第九十一篇原创文章。行业大牛和刚毕业的小白,都可以进来聊聊。
欢迎关注本专栏和微信公众号《敏捷测试转型》,星标收藏,大量原创思考文章陆续推出。本人新书《无测试组织 - 测试团队的敏捷转型》已出版(机械工业出版社)。
众所周知,测试活动越早进行,在早期发现缺陷的数量就越多,而且单个缺陷的修复成本也会越低。如果缺陷在接近发布前被发现,修复的总成本要提高一个数量级,如果缺陷上线后才被发现,带来的损失价值可能再高一个数量级,达到令人吃惊的程度。
根据 Capers Jones 在《全球软件生产力和质量度量分析报告》中给出的图表数据,假设在编码过程中修复一个缺陷的成本是 1,那么在单元测试中修复一个缺陷成本是 4,而功能测试和系统测试的单个缺陷修复成本分别是 10 和 40。如果遗漏到线上,修复成本飙涨到 640!
通常在开发阶段,开发人员做的事情是开发设计文档,编码,CR(代码评审)和开发自测等工作。与此同时,测试人员的常规活动是准备测试策略,测试用例设计,用例评审和自动化测试相关准备,等等。
本文提到的测试左移,是指测试人员除了要学习开发人员提供的设计技术文档(用作测试设计的参考)以外,还可以积极参与开发相关的如下重要活动,更早地暴露问题,减轻而非加重开发人员的负担。
1)参与开发设计评审。
2)推动测试驱动开发(Test Driven Design,TDD),落实单元测试门禁。
3)代码评审活动。
4)代码规范落实。
5)桌面评审(Showcase),即完成验收测试。
6)共建每日持续测试,完善测试分层建设。
测试人员的目的从发现缺陷变成了预防缺陷,这会导致与开发人员协作关系的重大变化。
参与开发设计评审
在传统研发团队,软件的开发设计包含概要设计和详细设计,测试人员并不被鼓励参加开发设计评审。实际上这个评审活动有利于测试人员获得重要的业务架构、功能和非功能的实现信息,对于测试策略和用例设计可能会大有启发,也会为精准测试提供关键信息。
测试人员参与开发设计评审,优先关注软件的整体架构、分层模块、底层模块的视图,鼓励追问设计方案的选型原因、资源限制场景、可靠性保障机制、安全处理机制等背后的技术知识,借此埋下 “如何基于设计风险做测试设计” 的种子,降低测试探测的盲目性。开发在设计讨论中的争论,也许提示了潜在的高风险信息。
从参与设计评审开始,测试和开发也就能在对等信息的基础上进行质量问题的本质探讨。
行业中有一种观点,认为如何测试人员过于熟悉开发的实现思路,就会站在理解开发的角度来测试,不会想尽办法找到破坏路径。我不这么认为,只要刻意训练,测试人员可以充分利用白盒信息和黑盒观察的各自优势,可以快速切换成不同的测试角色(开发者或普通用户)来高效地挖掘问题。
TDD 与单元测试门禁
TDD 常见的类型有两种,UTDD(Unit Test Driven Design,单元测试驱动开发) 和 ATDD(Acceptance Test Driven Design,验收测试驱动开发),两者的差异如下。
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)应用的内存泄漏作为测试重点项,我们会分析出常见的内存泄漏原因,及其代码实现中的错误表现。按这些反例提炼评审关注点,比如对象如果注册了实践回调,是否在合理的地方进行了反注册;缓存对象、图片资源、各种网络连接、文件 IO 等,最终是否正确关闭,诸如此类。
4)专业的静态代码扫描工具也可以提供典型代码问题的分类定义和推荐解决方法,结合起来学习效果更佳。
最后,为了让代码评审流程规范化和更高效,也可以在研发管理平台上即时发起在线评审,确保多人的评审结论满足基本门槛后,平台才允许把代码提交入主干。
代码规范落实
不少大公司会制定代码规范(Coding Standard),包括质量层面、风格层面和安全层面。测试人员针对代码规范往往可以做一些较高收益的尝试:协助制定适宜的代码规范,并积极推动激励制度落地,形成开发习惯,等于用很低的成本把不少潜在风险拦截在初期开发阶段,性价比高于强推开发单元测试。
围绕代码规范的推动,质量人员可以做三类动作:
一,推动代码规范的文档化和宣导。大公司的代码规范文档往往很容易获取,但是细则繁多,对开发的严谨习惯提出了较高的要求,测试可以根据团队专业成熟度,以及常见缺陷风险,选取其中的子集作为本团队的规范,在执行成本和风险拦截中取得平衡。
二,把规范检查纳入到流程管控或者工具审计中。与开发达成代码规范卡点的纪律,在日常代码自动扫描中要明确告警规则,确保开发负责人即时响应处理,不允许随便取消告警规则。
同时,在引入静态代码检查工具阶段,测试人员也会参与货比三家,务必在价格、质量/安全风险检出率、误报率、修复提示水平,售后技术指导等多个要素上推荐出更佳的开源或商业工具。如图是我们在 2017 年针对代码扫描工具选型的评测结果。
图 SonarQube 和 Pinpoint(源伞)扫描工具效果评测
三 作为中立方输出代码规范专项审查报告。代码规范的分类多样,我的经验是可以细分为排版规范、注释规范、命名规范和编码规范四类,规约强度可以是 “建议” 或者 “原则”。测试可以借助扫描工具和人工核查,针对特定一类违规现象做审计,输出分析改进专题,这种聚焦曝光和集中改进的效果往往让人印象深刻。泛泛而谈的审计报告则很容易失去可持续的抓手。
比如我曾带团队陆续输出的几期专题报告:APP 代码扫描专项,代码注释规范专题,冗余代码专题,圈复杂度分析专题等等,充分利用多种扫描工具,配合人工核实问题有效性,聚焦清理一类问题,因此开发解决的速度会很快,让团队也很有成就感。
桌面检查(验收 Showcase)
当开发完成编码和调试,如果马上部署测试环境开始进行端到端的验收,那么就进入高成本的测试活动。当测试发现了可能的缺陷,寻找开发人员进行确认时,开发人员可能已经在开发另一个需求了,必然产生更多任务切换和沟通的成本。
如果开发完成编码调试后,进入桌面评审(Deskcheck)活动,比要求开发人员承诺 “自测” 的方式更有利于提升开发质量。有些公司也称之为 Showcase。只需要在开发的本地环境验证(测试数据由开发自行准备),组织特性团队和干系人的集体会议,由技术人员进行功能演示。通常在演示中会执行验收测试用例。如果验收测试用例不通过,则可以打回开发进行修复,未来再安排新的一轮 Showcase。如果验收测试没有发现严重问题,可以进入系统测试阶段。
这个质量评审活动体现了敏捷宣言的核心实践,个体的交互及合作,比固定流程更重要。
基于本人的实际感受,因为 Showcase 形式公开直接,开发人员会进行充分的测试准备和确认。参与 Showcase 的人员如果原本不太熟悉业务细节,通过参与验收展示的全流程,会对于业务交互逻辑有非常深入的理解。
最后关于持续测试,将来再重点讲解。