随着近年来DevOps的兴起,软件的迭代速度逐步加快,开发架构逐步微服务化,部署也逐步走向轻量级容器化。而测试作为衔接开发与运维的重要一环,承担着保障软件质量的重责。因此在IT工作模式改革和信息技术革新的今天,软件测试也正在掀起关于效能与质量的改革浪潮。
早些年人们在软件测试的改进上,更多地可能只是在关注测试的技术发展,试图通过买入或封装自动化测试工具来应对DevOps的快节奏,却忽略了思考如何让测试真正地服务于软件研发,即如何让测试更好地适应DevOps下软件研发的工作模式和技术特点。
因此在今天的分享中,我们将通过分享DevOps下测试的“现状分析”-“技术优化” - “机制改革“三部曲,来带大家逐步领略DevOps发展下软件测试所遭遇的瓶颈,以及对应改进的“术”与“法”。
01. 复杂且琐碎:DevOps下测试的现状分析
过往,为了快速应付DevOps转型后的快速迭代节奏和复杂技术架构,不少研发团队引入了大量自动化测试工具,寄希望于技术为测试团队提效。
但过于追求短期的快,却忽略了需要在企业整体上对测试进行业务设计和技术管控,导致长期运行下来以后,大幅加剧了测试的管理复杂度。
那么回到“让测试更好地适应DevOps下软件研发的工作模式和技术特点”的主题上,企业又该如何重新为测试设计业务和工艺呢?
这里需要我们先跳脱出手工测试和自动化测试的二极管思维,来学习下自动化测试的分层概念:
上图左侧的分层自动化测试金字塔模型最早来自于Mike Cohn2009年出版的《Succeeding with Agile》。我们可以观察到,在该模型中,自动化测试被分为了单元层、接口/服务层以及UI层三个大类。
这是由于不同类型的测试,在自动化测试上的投入产出比是不一样的。越往复杂度高的维度走,自动化测试的效率将越低,投入也越高。
因此,在综合考虑测试工作量、测试频率以及自动化测试投入产出比等因素后,我们建议在整体测试工作的业务设计和技术使用上,企业应当:让自动化测试优先覆盖单元层和接口/服务层,UI层仅覆盖主流程或者核心业务分支即可。
名词解释
UI(界面)测试:测试用户界面的功能模块的布局是否合理,整体风格是否一致,是否符合客户使用习惯等。
接口测试:检测系统与外部系统之间以及内部各个子系统之间的交互点,例如检查数据的交换、传递和控制管理,以及系统之间的相互逻辑等。
单元测试:指对软件中的最小可测试单元进行检查和验证。最小可测试单元由人为界定,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中则可以指一个窗口或菜单等。
当然,随着微服务和容器化的广泛应用,也有部分业界人士认为,单元测试已经不能很好地承担现在主流软件的测试重任,质疑全面自动化单元测试的业务价值,转而将更多自动化测试资源优先投入到接口/服务层,整体分层自动化测试结构呈现橄榄型。
例如,部分团队会优先选择通过单接口测试向下覆盖单元测试,以此保障微服务架构下API接口的稳定性。
这种做法更多是强调在微服务架构下,自动化接口测试中难度相对最低的最小逻辑单元接口测试,可能会比解耦了依赖关系的自动化单元测试更具有业务价值。
这里的单接口测试,主要是指对单元测试之间的测试间隙(可以先简单理解为函数与函数之间的调用关系)进行测试,以此覆盖单元测试没有覆盖到的数据依赖和外部服务依赖等测试内容。
但考虑到单元测试不仅具有测试复杂度低的优点,更重要的是它还具备测试左移的最大先发优势。越早开始测试,发现问题和修复问题的成本越低。
所以这也是为什么,虽然单元层和接口/服务层都可以根据业务需求全面地推进自动化测试,但我们仍旧建议,企业在推行自动化测试时,应当优先全面覆盖单元测试,而接口测试次之。
以上也是近年来随着DevOps讨论度的增加,TDD的概念开始被IT人所接受和推崇的原因之一。
作为敏捷开发的其中一项核心实践,TDD强调通过测试来推动软件开发,重点关注代码层的测试工作,来保障DevOps下测试工作的高效完成。
名词解释
TDD:Test-Driven Development,测试驱动开发。具体可表现为在开发功能代码前,先编写单元测试用例的代码,提升代码的可测试性,以达到“测试左移”,从而提升软件整体交付效率。
但由于单元测试具有测试左移的业务优势和代码编写的能力要求,要么需要测试团队具备代码编写能力且真正做到与开发团队密切配合,要么就需要开发团队除了开发新功能以外,还需要自行承担起单元测试的工作。
在考虑到普遍企业的开发复杂度和测试性价比后,我们会更推荐企业选用由开发主导的形式开展单元测试,尤其是那些有不少外包开发团队的传统企业。
那么在这种情况下,我们在对单元测试领域应用自动化测试技术时,就需要更多地考虑到开发团队的实际业务情况,降低单元测试给开发人员的压力。
02. 固测试根基:DevOps下测试的技术优化
上文我们提到,自动化测试可分为UI层、接口/服务层和单元层三大类,而在DevOps研发模式下企业应当优先考虑实现自动化单元测试,而且自动化单元测试工艺最好基于开发团队主导的视角进行打造。
那么基于以上考虑,我们接下来就聊聊自动化单元测试这项负责打基础的质检技术。
这里可能有读者会发出疑问,既然要做自动化单元测试,那咱们直接在Jenkins里集成个Jacoco插件不就完事了吗?做一般迭代的回归测试都绰绰有余了,这块还有什么技术难点值得关注吗?
诚然,前面提及过,相对其他类别的测试而言,单元测试脚本的开发和保鲜已经是成本最低的了。
但对于开发而言,只要单元测试仍然需要耗费大量工时来手动编写和执行脚本,那想要在企业内全面推行,尤其是在那些按人天计费的外包团队内推行,就难免会遇到一些“不可抗阻力”和“结果不尽如人意”。
为了解放单元测试的生产力和保证执行质量,我们列举了当前具有代表性的自动化单元测试发展趋势,各位可以参考看下自己的企业是否潜藏着相关技术需求:
- 无代码改造、不依赖测试框架
- 全自动生成单元测试代码
- 不依赖被测系统技术和状态
- 精确定位问题代码
- 图形化配置、简单易用
我们不难看出,实现“测试自动生成”,从而减轻单元测试可能给开发造成的代码改造、脚本编写和问题定位等成本,提升代码覆盖率,是当前自动化单元测试技术优化的重点。
目前市面上专业做自动化单元测试的工具也是如同雨后春笋般冒出,多数都还在集中攻克Java语言,现在也不合适做工具能力的对比。
但总而言之,能有越来越多企业关注单元测试并产生市场需求,也有厂商愿意在这块领域进行投入是件好事。说明在软件研发领域,国内也是越来越舍得在这软件质量这块下功夫了。
如果有读者对自动化单元测试非常感兴趣,可以结合上面的技术趋势与自身的实际需求,去对工具作进一步判断和选择,这里不作过多引导。
03. 服务于业务:DevOps下测试的机制改革
上文通过介绍自动化单元测试的发展趋势,从技术角度初步带领大家看到了分层自动化测试的“测试自动生成”导向。
当我们把目光再次聚焦到“让测试更好地适应DevOps下软件研发的工作模式和技术特点”的主旨上,软件测试的工作机制又该如何优化呢?
为了应对DevOps的快节拍与复杂度,我们无论是应用手工还是自动化的测试技术,无论是执行单元层、接口/服务层和UI层的测试工作,无论是由开发还是测试主导的测试任务,都需要以快速应对需求变更为前提进行布局,简单总结就是下述四个步骤:
1. 需求建模
确保所有研发需求都被测试验证范围所覆盖,其中优先推荐通过自动化测试覆盖单元层和接口层,打牢软件测试的根基,但如果目前系统并不具备可测试性,那么使用手工测试也是非常合理的选择。
2. 测试建模
通过有限的状态机去消除复杂的测试用例,将状态机与需求进行1:1绑定,自动化生成测试用例/伪脚本,从而达到自动化测试建模,以及测试数据自动化生成和管理的效果。这一步主要是解决需求变更后,测试用例无法及时变更等问题,影响精准测试。
3. 场景建模
通过自动化创建拓扑映射,让复杂的测试场景自动化生成。由于测试用例之间存在着错综复杂的关联拓扑,尤其是在用例需要跨系统调用外部依赖的情况下,为了解决“牵一发却不知道动了全身”的问题,就需要我们对测试场景也进行建模,保障业务场景得到有效验证。
这里的测试场景自动化生成,主要是针对测试用例场景法的应用。在实际测试工作中,为了保障软件的业务流程和业务逻辑,会让测试通过模拟最终用户分别进行正确和错误的操作,从而检验软件功能是否能够正确实现,以及软件是否有足够的异常处理能力。
4. 工具规范化接入
为了能对测试业务和测试工艺进行企业级管控,我们要将需求建模和场景拓扑映射作为测试平台的核心设计原则,从而降低测试的保鲜(维护)成本,再通过有选择性地集成测试工艺,避免企业被某些能力不足的测试工具所“绑架”或者“卡脖子”。