查看原文
其他

开发高质量软件的5大原则

2017-08-30 John Paliotta DevOps时代

多少次的惨痛教训告诉我们,在软件应用发布维护版本或者补丁之前,应该避免使用其最新版本。虽然每个人都知道初始发布版本V和稳定发布版本V.n之间存在软件质量鸿沟,这个问题却一直没有得到解决。

本文将会讨论5个具有可操作性的原则,以帮助开发团队跨越质量鸿沟:

1. 使用代码覆盖率反映测试完整性

软件测试的目的都是为了保证软件能在最终用户使用时是正常运行的。然而,软件测试面临着挑战,如何保证测试的完整性?很多开发组织会制定测试规程去匹配需求文档或者用户文档。这种测试方法可以验证正常操作路径,但是测试边界、错误场景都无法验证。这种方法通常只能保证60%~70%的代码覆盖率。
唯一保证测试完整性的办法就是在测试用例执行过程中收集和分析代码覆盖率数据,以确定应用的哪些功能被执行,更重要的是确定应用的哪些功能没有被执行到。由此看来,代码覆盖率分析是确定应用程序的测试进展的最佳方法,也是测试完整性的唯一可靠度量指标。代码覆盖率分析可以贯穿从开发者测试到发布测试的应用程序全生命周期。
然而,100%的代码覆盖率并不能证明应用程序就是完美的,它只能证明在工程上软件是高质量的。事实上,许多和关键性安全软件开发有关的标准都将代码覆盖率视为开发过程的一部分。比如:DO-178B/C (航空航天a), ISO 26262 (汽车), IEC 61508 (工业控制), FDA and IEC 62304 (医疗设备) and the CENELEC standard (铁路应用)。

图1:分析源代码覆盖率是度量测试活动完整性的最佳方式

2. 使用单元测试提高测试覆盖率

一旦开始度量代码覆盖率,当前测试覆盖率会明显低于100%,这都是测试只专注在正常路径的测试,忽略错误情况和边界情况造成的。最明显的提高覆盖率的方式就是增加额外的功能测试,但是应用程序代码中的20%~30%的确很难在生产环境中通过功能测试执行到,因为触发错误处理是很难的。

图2:覆盖率鸿沟是由于测试专注在正常路径的测试,忽略错误情况和边界情况造成的

严重的bug一般都是在非常规操作的情况下发生的,这些操作是从来预料到的。
这就是为什么使用单元测试的原因,单元测试对于构建健壮稳定的应用程序非常重要,因为单元测试能够触发应用程序最小粒度的功能并且证明最小粒度的需求被恰当地实现了。
在做单元测试时,一般都会使用mock等技术来独立运行程序方法。这样有很多的好处,开发者可以很方便的在开发过程中发现、定位、修改问题,单元测试还允许触发错误来测试错误处理等情况,这在生产环境中是不可能实现的。

3. 保证测试易于执行,测试结果易于理解

知难行易,很多工程师使用了不同的方法和工具想要保证测试易于执行,测试结果易于理解,比如:
开发者测试:用于保证应用程序在方法级别的正确性
集成测试:用于保证功能级别的正确性
系统测试:用于保证系统级别(最终用户使用)的正确性

图3:共同的测试协作平台是实现该工作流的关键

当测试照此分类之后,不同的测试由不同的工程师团队负责。实际上,测试工程师基本不可能执行开发者测试,开发也不会执行系统测试。为了提高软件质量,我们需要打破这种隔离,团队中的所有人都可以在任意时间执行软件任意版本的任何一种测试。共同的测试协作平台是实现该工作流的关键,该平台应该包括所有测试的前提条件和期望结果。工程师应该可以一键执行任何一个测试,除此之外,工程师还应该能够快速的debug失败的测试。

4. 实现自动化、并行、基于变更的测试

当通过测试覆盖度分析提高测试完整性、通过组织共同参与测试之后,下一步我们就要保证测试能够快速的执行。之所以测试会被换分为如此多的类型,由不同的部门负责,原因之一就是一个完整的系统测试需要花费几个小时、甚至几天才能完成。
如何提高测试执行速度呢?——构建一套可扩展、并行的、基于变更的测试基础设施
单个测试必须是原子性的、足够小、足够快的。将新测试用例加入到现有测试套件时,往往会出现测试时间成倍增加的情况。这导致测试很脆弱且难于维护。在设计测试用例时,我们一定要保持某个测试必须有其自己的前提条件,而不是依赖于其他测试的输出。

图4:每个测试必须定义它自己的前提条件而不依赖于其他测试的输出

除了测试维护性和重构测试之外,原子性还可以带来如下好处:

基于变更的测试,只执行被软件变更影响到的测试用例
并行的执行测试,同时执行更多的测试用例

大部分组织都实现了持续的自动化的增量式的软件构建系统,但是测试的依然是阶段性的。
基于变更的测试
基于变更的测试(CBT)分析受到变更的代码,智能的选择受到影响的测试子集。这比运行所有的测试快很多。基于变更的测试能够帮助我们实现严谨的持续集成开发过程。在持续集成的check-in阶段,CBT能够快速的验证新的提交并更早的检测出问题。
并行的执行测试
通过持续集成、虚拟化测试环境能够极大的提高测试用例并行速度,降低测试执行时间。

5. 不断重构代码以提高可维护性

代码重构是在不修改软件外部行为或者API的情况下重构内部组件结构。如果没有重构,随着时间的推移,代码会变的异常复杂和难以维护,当新特性和缺陷修改的代码加入进来之后,也会破外原本优雅的架构。
代码重构提高了代码可读性,降低了复杂度,降低了维护成本。好的代码重构能够通过简化逻辑和减少复杂度,以解决系统中隐藏的、遗留的、未被发现的、易受攻击的问题。
重构的最大障碍来源于缺少测试保证软件的功能正确性。软件都会存在脆弱和充满缺陷的部分,开发者往往会犹豫是否要修改这些地方,因为他们害怕破坏现有的功能。想要自信地进行重构,我们需要建立一套测试用例,以保证软件的功能正确性。

 

结论:

在过去的三十年里,工具、设计模式、开发范例都在变化,很多工具都承诺可以不增加工作量的情况下提高质量。然而,并没有银弹。提高软件质量是每个人的责任。提供软件质量的最有效的方式还是提供软件测试效率。

原文地址:https://dzone.com/articles/five-principles-for-engineering-high-quality-softw

译者曰:

  1. 软件质量不仅仅是软件功能符合需求而已,代码的可维护性等技术债务指标应该不断被强调,并且采用内建质量的方式在开发过程中建立起质量,而不是依靠检查来提高软件质量。

  2. 测试驱动开发,很多创业团队采用这种方式保证MVP(最简化可行产品),同时TDD也保证了软件的质量总是符合预期的。

  3. 测试覆盖率要和圈复杂度结合使用,圈复杂度过高的,测试覆盖率必然会降低,因为需要写更多的测试用例才能覆盖到代码的全部可能执行路径。建议圈复杂度低于10。

  4. 代码重构必须基于良好的自动化测试,否则测试MM会掐死你的 。


END


近期好文:

乐神:DevOps 道法术器,立体化实施框架(完整解读)

实例化需求,软件外包质量管理的神器

运维助力敏捷交付-我们的运维看板

腾讯织云:DevOps流水线应用平台践行之路

没有高效的部署流水线,何谈DevOps


第八届全球运维大会

即 GOPS2017·上海站将于2017年11月17日-18日在上海举行

各种精彩等您发掘。


点击阅读原文关注活动官网

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存