SAP成都研究院郑晓霞:Shift Left Testing和软件质量保证的一些思考

☆樱花仙子☆ 提交于 2020-02-05 05:21:52

今天的文章来自Jerry的同事,曾经的搭档郑晓霞(Zheng Kate)。郑晓霞是在Jerry心中是一位很有实力的程序媛,2011年从西安某软件公司跳槽到SAP成都研究院。当时,成都研究院的CRM团队刚刚成立,Jerry和郑晓霞都在一个大组。

2012年夏天,我们接到任务,要把SAP Customer Briefing这款已经发布的iOS应用移植到Android平台。因为只有1年的期限,老板组建了一只特殊的开发团队,由Jerry, 郑晓霞和另外两位男同事组成。是的,因为需求很清楚,就是把iOS版本上的功能移植到Android平台,所以这只团队没有产品经理,没有架构师,郑晓霞担任了开发人员和Scrum Master的双重身份, UX也是项目中后期从上海找了一位同事远程加入项目组。由于我们4位以前都没接触过Android开发,因此也是边学习边干活。这个微型团队的学习气氛非常好,一个人遇到困难,其他三位都会积极热心参与讨论和提供帮助。

Jerry印象最深的一件事是,当时我负责实现一个company profile的功能,即客户可以从一个下拉列表里选择一个企业,从而进入该企业明细页面,显示该企业的概述,包含文字简介,企业人数,财政收入等等。概述信息通过消费wikipedia提供的Restful API,传入企业名称,返回响应,其中需要显示在明细页面里的关键信息得通过编程人员自己写正则表达式提取出来。

Jerry当时的想法是,把iOS版本里解析正则表达式的Object C代码直接改成Java代码,因为不同编程语言里使用的正则表达式,其语法虽然稍有差异,但语意是相同的。但当我阅读了一段时间iOS代码那些操作正则表达式的Object C代码后,已经头昏脑胀了,我的Java代码写好后进行测试,发现并不能保证对所有测试输入的company, 都能够用正则表达式正确地解析出关键信息。

然后Jerry说,算了,我不参考iOS代码,我直接自己从头写吧。写完后测试,发现仍然不能保证对于所有的测试数据都能正常工作。

看到Jerry陷入进退两难的境地后,晓霞同学像女神一般出现在我面前,说:“我来试试”。一个下午过去,晓霞同学提交了一段代码到perforce上,那是一段结构清晰,并且能够完美使用正则表达式完成关键信息解析的Java代码。我使用了一百多个company进行测试,全部工作正常。实际上,直到最后发版,晓霞同学这段代码也没有发现任何bug。

当时晓霞同学在Jerry心中的形象和这位潇洒的警察一样:

这件事让Jerry从此对晓霞同学刮目相看,一直到现在。

下面是晓霞同学的正文。


大家好,我是郑晓霞,现在是SAP成都研究院Hybris Enterprise Commerce Platform开发团队的质量工程师(Quality Engineer, 下文简称QE)。今天我想和大家聊聊我在这个岗位上工作一段时间之后的一些心得和体会。

在敏捷开发模式下,团队需要有持续快速的交付能力。那么在持续交付过程中,如何保证产品质量呢?大家的答案可能是自动化测试。

但是自动化测试是否足够、有效,即使足够、有效,就能说明产品质量好吗?测试结果只是一个指标,这个指标代表的只是在当前的测试环境下,现有测试实例的运行结果,是我们保证质量的下限。

软件质量不是测试出来的,而是在开发过程中建立起来的。控制开发过程中的质量有助于提高产品的质量上限。

Shift Left Testing,通俗理解就是把位于传统软件开发流程中最后阶段的测试往前提。提到哪一步呢?开发?设计?需求?我个人的理解是越往前越好。这意味着在整个开发周期内需要持续测试,持续关注质量,这一切都是为了提高质量的上限。

这会带来什么好处呢?

1. 减少测试和开发的成本, 提高投入产出比ROI(Return On Investment)

在软件开发的整个过程中,越早发现问题,修复的成本越小。

试想在所谓的集成测试阶段发现一个bug,花时间部署测试环境,准备测试数据,执行测试,重现bug,跟开发人员沟通,将bug分配给开发人员后,他/她们可能需要重新部署开发环境,重新开发,重新做代码审查,最后再走一遍测试流程。如果能在代码审查或者单元测试阶段发现这个bug,得节省多少时间?

2. 提高测试效率

如果能在需求,设计阶段能发现并阻止bug,可以节约很多开发生命周期的反复,同时在理解需求、代码的基础上进行测试,可以更有重点和针对性地面向业务和风险测试,而不会陷入测试细节,有效提高测试效率。

3. 提高质量

在需求层面保证并优化需求以及需求传递的质量,在代码层面保证设计的灵活性,代码的整洁性, 在开发过程中控制质量,提高产品内部质量。

Shift Left Testing是需要整个敏捷开发团队作为一个整体去遵循的。那么在一个敏捷开发团队中,作为一位QE,在整个产品的开发生命周期中需要怎么和团队合作呢?

1. QE作为敏捷开发团队的一员,可以做任何能帮助团队提高质量的事情, 没有界限,目的是为了帮助团队发现问题,解决问题,提高产品交付质量。

QE要能做到没有界限地提供质量保证,需要自身做出两个重要的改变:

(1) 全方面地提高自己的技能

如果缺乏相关的技能,比如业务能力和一定的代码能力,很难想象QE能够高效地参与到各个开发环节的讨论中,更谈不上能给出建议和意见。当然这不意味着必须让QE成为一名全栈工程师。QE需要去找到学习的平衡点。有些技能可能不是必须的,但是如果具备这些技能,会让QE以更加高效的方式做事。

(2) 深入到软件开发生命周期的各个环节,紧跟团队的开发节奏

如果不深入到开发的各个环节,有些质量问题的根源没法找到,那么提前阻止bug也就无从谈起。只带着耳朵听,是没法深入的。需要思考,从质量的角度去思考,但是如果技能差距太大,能勉强跟上节奏也就不错了,谈不上思考。所以深入软件开发周期各个环节需要QE自身技能的支撑。

同时,QE在参与的过程中,需要把握好平衡,能发现问题,也需要让团队各个角色能够各司其责,维持健康的团队工作模式。

2. QE需要培训团队,让团队能够拥有测试技能和质量意识,并能够自己解决问题,同时不断提高质量。

产品质量由敏捷开发团队来保证,经常听到有同事说,”我们的QE还挺厉害的,测出了不少问题”。在一个敏捷开发团队中,只有一个QE,靠一个人的英雄主义,测这么多问题,如果QE休假了怎么办?能对团队的质量放心?

QE的成就感不在于“我有多么重要,测出了多少重要的bug”,而是“没有我,团队的产出仍然是高质量的”。要达到这个目标,QE的任务就是挖掘团队的质量需求,培训团队,让QE变得越来越“多余”,使团队成为一支“去QE化”的敏捷团队。

这两点看似矛盾,实则第一点(帮助团队发现问题)是为了有方向性地支持第二点(如何培训团队自己解决问题)。随着团队越来越成熟,这两点也就慢慢地越做越少。

那么质量是不是越高越好呢?质量是要付出代价的,需要控制成本和产出。举个温伯格提到的例子,MiniCozy公司的文字处理软件,在对一整本书进行排版时,会出现漏词的错误,而这个错误确实发生在一个作家的处女作上。但是MiniCozy公司的回应是,在数以十万计的用户中,或许都找不到十个人会把这样大规模的任务用单独的一个文件来组织,修正这个错误可能会花很多时间和成本,并且还有可能引发更大的错误,从而影响到几百甚至是几千位用户。MiniCozy认为他们的取舍是正确的。所以质量不是指毫无纰漏,而是有其相对性。

下面我列出了在软件开发生命周期的各个环节里,QE能够做的事情,但是QE不是一定需要参与,参与的目的是为了发现问题,最终是需要培训使得团队能够具备质量和测试相关的知识和思维,通过改进流程,行为让团队自己保证质量,并不断改进。

根据每个组不同的成熟度和QE技能的高低,事情可能会有所不同。

为了图表的简化,只列出了事情本身,下面会有简单说明做这些事情的目的。

Before coding - 开发开始前

1. Involve requirement discussion early

在做产品开发前,我们应该理解需求背后的原因,客户遇到什么问题,我们能够帮客户解决什么问题。我们测试的不仅仅是产品功能,更是业务价值。提前参与需求的讨论对决定测试的重心,优先级都有极大的帮助,避免陷入辛苦的测试细节中。这样我们就可以有效的利用Pareto的20/80原则,提高测试效率。

2. Ask negative questions

每个人都可能受惯性思维影响,我们可以通过问负向问题来优化功能性需求和非功能性需求的测试, 比如产品标准和GDPR(General Data Protection Regulation)等。

3. Collaborate with testable and executable acceptance criteria

Acceptance criteria主要关注的是业务价值,建立user story的功能范围,并能指导开发。通过各个角色合作讨论的方式列出acceptance criteria,能够避免对需求范围的误解,同时参与的每个人都能很清楚的知道要测什么,要怎么测。

4. Work out test plan in sprint

在敏捷开发的每一个sprint内,我们也需要基于sprint目标制定测试计划,包括哪些功能需要手动测试,哪些功能需要自动测试,哪些功能需要回归测试,是否需要做性能测试/安全测试等。同时还需要计划对之前的测试做维护。这个测试计划会影响到sprint planning meeting对任务的分解和时间估算。

5. Join estimation proactively

在sprint planning meeting中,基于制定的测试计划,积极参与对任务的分解和时间估算,包含相关测试的开发、维护和执行时间。

6. Design and prepare test points with good test data including automation test

这些实际是传统的瀑布开发模式需要的测试相关的专业知识,同样也适用于敏捷开发模式。通过各种方法论的使用,设计出测试点,来指导、优化测试执行,提高测试效率。在敏捷开发模式下,QE需要让所有成员都具备这种测试设计技能。

7. Define KPI/Dashboard

团队需要定义如何来度量质量,KPI(Key Performance Indicator, 关键绩效指标)的度量值能直接反馈出团队的外部质量,并可以通过根源分析帮助团队认识问题,解决问题。

During coding - 开发过程中

1. Join or familiar with design

虽然敏捷开发模式并不像瀑布开发模式那样具有专门的软件设计阶段,但是小的功能点设计在每个sprint确实存在。不同的设计有不同的测试考虑,比如通过事件来触发订单流程,或是通过后台作业来触发订单流程,测试要验证的点肯定是不一样的。如果采取后台作业方式,还需要验证作业信息和计划的执行时间是否正确等等。

同时我们需要在设计时考虑可测试性。软件的可测试性是指软件发现故障并隔离、定位其故障的能力特性,以及在一定的时间和成本前提下,进行测试设计、测试执行的能力。James Bach 这样描述可测试性:软件可测试性就是一个计算机程序能够被测试的容易程度。

比如,为了测试一个类的方法,首先我们需要创建这个类的实例,需要引用必须的内部依赖,同时还要隔离外部依赖。有的场景下做到这些并不是那么简单,由于开发人员容易局限于考虑自己负责的功能的具体技术实现而忽略了设计的可测试性,而QE参与功能设计则可以提高开发人员对确保其设计的可测试性的意识。

2. Guide/coach/pair to develop testable code and effective test code

可测试的代码是写测试代码的前提条件。测试代码的作用绝不仅仅是用来满足测试覆盖率的,测试代码需要基于测试设计和测试数据来测试软件的功能,所以需要QE能和开发人员一起保证测试代码的有效性。一旦发现bug,除了修复bug本身,还需要评估是否需要改进现有的测试代码来覆盖这个bug。

3. Go through code for both functional code and testing code

以QE的角度检查代码,比如需求是否匹配,是否考虑了SAP产品标准等等,从这个角度检查既有助于发现问题,同时可以提高测试效率。比如,代码添加了新方法来获取当前时间,时间和格式是否做了本地化处理?这个新方法是否被调用了?如果都没有符合,那还需要继续功能测试吗?在这些缺陷弥补之前,当然没有必要进行功能测试了。后面我们还会追溯为什么会有这种情况发生。

4. Safeguard DoD compliance

因为我们是做产品,只有满足了DoD(Definition of Done, 完成的定义,敏捷开发里的一个术语,表示工作是否完成),user story才能算完成。我们必须要严格遵循,这样才能持续交付,并且避免技术债务。

5. Utilize continuous integration environments

通过集成各种代码扫描工具,利用持续集成来发现问题,提供质量的快速反馈。

6. Test an uncompleted user story

通常一个user story不会太大也不会太小,在团队还不够成熟的时候,QE还是需要测试user story。为了不在sprint末期出现测试的“惊喜”和大量测试任务的涌现,我们可以和开发商量,讨论出哪部分功能可以先开发。等这部分功能开发结束后就可以开始测试,即使这个user story还没有完成。

7. Provide fast feedback

除了持续集成之外,QE需要对开发的bug提供及时快速的反馈,因为开发人员熟悉业务和代码,能够比较快速地解决问题。另一方面这也可以作为考虑如何提高质量的on-job培训的一部分。

After coding - 开发结束后

1. Test user story based on business value and risk

在团队还不够成熟的情况下,QE还需要基于业务价值和风险来测试user story,测试的粒度和范围可以根据团队的具体情况进行调整。

2. Hold another bug hunt or other manual exploratory testing session

基于user story的KPI,重要性和风险程度,我们需要决定是否再需要一轮测试。

3. As problem solver to analyze issue and find how to resolve issue

QE发现了bug,报告给开发后,QE的任务就完成了吗?QE可以通过现象,日志等分析问题,定位问题,提高问题的解决效率。

4. Reflect AC/DoD/Test plan/test case/test data

回顾之前做的一切和测试相关的活动,从中总结经验教训,做到持续改进。比如上个sprint的test plan实际执行情况如何?设计的test case覆盖到了所有场景吗?准备的测试数据质量如何?测试活动中有哪些方面下个sprint可以做得更好?

以上仅仅是个人观点,欢迎共同探讨学习。

下面是我在思考自己作为一个QE在团队中定位过程中参考的一些网站和博客。

相关阅读

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!