一、当前软件开发的趋势
开篇我们先简要介绍一些近几年在企业开发中出现的重要概念,以便引入持续测试的主旨。这些概念中最重要的两个便是DevOps和微服务。两者都是目前软件开发中的最佳实践和方法论,旨在为企业提供更高的灵活性,提升运营效率。
1.1 DevOps
DevOps是一套实践方法论和文化,提倡打破原有组织和限制,职能团队开始拥抱和接受DevOps所倡导的高度协同,研发、测试、运维及交付一体化的思维。
随着DevOps和敏捷热度的不断提升,无论是互联网企业还是传统软件企业都开始拥抱敏捷,实践DevOps。持续集成CI(Continuous integration)、持续交付CD(Continuous delivery )作为DevOps的最佳实践,越来越受到重视。
1.2 微服务架构 Microservice Architecture
微服务架构源起于DevOps意识形态和实践中,是一种软件架构风格。微服务架构带来了一系列好处,例如可部署性、可靠性、可用性等等。虽然原则上可以使用任何架构来实践DevOps,但微服务架构正在成为构建持续部署 (CD)系统的标准架构风格。由于每项服务的规模都很小,它允许通过连续重构来实现单个服务的体系结构,因此减少了对大型项目前期设计的需求,允许尽早发布软件并且持续交付。微服务和DevOps是天然的共同体,结合起来共同实现软件开发行业的变革。
二、自动化测试 Test Automation
随着敏捷和微服务架构的引入,CI/CD成为构建和部署的标准,即使在没有采用微服务架构的项目中也是如此。为了保证已定义的流程和事务按照预期运行,测试必不可少。而在应对现代软件产品频繁的变化和发布上,传统的手工测试方式在人员和效率上都存在严重不足,因此自动化测试已经成为现代软件研发过程中一个关键组成部分。自动化测试是打通持续集成和持续交付的核心,没有有效的自动化测试保证,持续集成和持续交付就仅仅是一个没有灵魂的躯壳。
2.1 测试分类
测试按照不同的维度可以进行多种分类。
按测试手段是否手工,可划分为自动化测试和人工测试;
按照测试目的划分,可分为功能测试、性能测试、负载测试等。
本文采用Martin Fowler按照层级分类的方式对测试进行分类。
Martin Fowler描述测试金字塔分为单元、服务和UI三个层级。尽管大家对此的具体描述各不相同(有人将三层分别定义为单元、接口、集成测试;也有人将整个金字塔划分为4-5个层级),但金字塔自底向上的结构是大家公认和遵循的。
单元测试
单元测试是针对代码单元(通常是类/方法)的测试,单元测试的价值在于能提供最快的反馈,在开发过程中就可以对逻辑单元进行验证。好的单元测试可以帮助改善既有设计,在团队掌握 TDD的前提下,单元测试能辅助重构,帮助提升代码整洁度。
接口(服务/API)测试
接口测试是针对业务接口进行的测试,主要测试内部接口功能实现是否完整。比如内部逻辑是否正常、异常处理是否正确。接口测试的主要价值在于接口定义相对稳定,不像界面或底层代码会经常发生变化,所以接口测试比较容易编写,用例的维护成本也相对较低。在接口层面准备测试的性价比相对较高。
集成(UI)测试
集成测试从用户的角度验证产品功能的正确性,测的是端到端的流程,并且加入用户场景和数据,验证整个过程是否健康流畅。集成测试的业务价值最高,它验证的是一个完整的流程,但因为需要验证完整流程,在环境部署、准备用例及实施等方面成本较高,实施起来并不容易。
2.2 微服务架构为测试带来的挑战
微服务架构在解决了应用大小、应用开发规模等问题之后也带来了一些新的问题,比较突出的有微服务数量增多、服务间调用关系复杂等等。复杂的依赖导致即使项目资深开发人员也不能一下子梳理出所有关系。
微服务和传统的单体应用相比,在测试策略上会有一些不太一样的地方。简单来说,在微服务架构中,测试的层次变得更多,需要测试的服务和应用也会变得更多。手动执行所有的测试是低效的,无法跟上互联网快速迭代的要求。这时有必要引入自动化测试来减轻测试团队的压力,提高测试效率和测试质量。
2.3 自动化测试
说起自动化测试,功能测试人员可能会将其想得很高端复杂。
先来看一般的功能测试如何进行:设计并编写用例文档,描述测试步骤和预期结果;测试人员根据测试用例描述按步骤操作,然后判断实际结果与预期是否一致。如果一致,测试通过;如果不符,测试失败。
自动化测试要做的事情与功能测试是一致的。分层理论和自动化测试方法结合,出现了三个层面的自动化:单元测试自动化、接口测试自动化和UI测试自动化。当然,不同层面的自动化关注点是不一样的。所以,从测试的行为本质上来看,功能测试与单元自动化测试、接口自动化测试和UI自动化测试并没有区别。唯一的区别是,一个由人来执行,一个由代码或工具执行。
2.4 自动化测试分层
单元自动化测试
单元测试自动化,指对软件中最小的可测试单元进行检查和验证,调用被测服务的类或方法,根据类或方法的参数,传入相应的数据,得到一个返回结果,最终断言返回的结果是否符合预期。如果相等,测试通过;如果不相等,测试失败。
所以,单元测试关注的是代码的实现与逻辑。单元测试是最基本的测试,也是测试中的最小单元,它的对象是函数对象,也可以包含输入输出,针对的是函数功能或者函数内部的代码逻辑,并不包含业务逻辑。
该类测试一般由研发人员完成,需要借助单元测试框架,如java的Junit、TestNG,python的unittest等。
接口自动化测试
接口自动化测试,主要验证模块间的调用返回以及不同系统、服务间的数据交换。接口测试自动化一般在业务逻辑层进行测试。根据接口文档是RESTful还是RPC?调用被测试的接口,构造相应的请求数据,得到返回值,是成功或者失败。不管输入的参数是怎样的,我们都将得到一个结果,最终断言返回的结果是否等于预期结果。如果相等,测试通过;如果不相等,测试失败。
所以,接口测试关注的是数据。只要数据正确了,功能就做成大半,剩下的无非是如何把这些数据展示在页面上。
常见的接口测试工具有postman、jmeter、loadrunner等。
集成(UI)自动化测试
UI层是用户使用产品的入口,所有功能通过这一层提供给用户,目前测试工作大多集中在这一层,这种测试更贴近用户的行为,模拟用户点击了某个按钮、在输入框里输入了某些指令。有时可能用户看到登录成功了,但UI自动化并不知道它刚才的点击有没有生效。所以要找“证据”,比如登录成功后页面右上角会显示“欢迎,xxx”,这就是登录成功的有力“证据”。当UI自动化登录成功后,就去获取这个数据进行断言,断言如果相等,测试通过;如果不相等,测试失败。
所以,UI自动化的关注点用户操作形为,以及UI上各种组件是否可用。常见的测试工具有UFT、Robot Framework、Selenium、Appium等。
分层占比最佳实践
每种自动化测试都有自己的侧重和优劣势,在实际工作中不可能做到均分,因此我们需要制定合理的测试策略对其进行组织和分配,包括每部分测试投入多少、测试用例比例是多少等。
测试金字塔还有另一个维度的信息,如上图所示。
越往上,越接近QA、业务/最终用户,越往下,越接近开发;
越往上,测试执行越慢,越往下,测试执行越快;
越往上,测试成本越高(越耗时,失败时的信息越模糊,越难跟踪),越往下,测试成本越低。
按照测试金字塔模型以及投入/产出比,我们得知越向下回报率越高,所以应该使用大量的单元测试和全面的接口测试来覆盖产品提供的基本逻辑和功能,使用少量的集成(UI)测试来进行前端界面的功能验证。
都说业内最佳实践看Google,Google的自动化分层投入占比是:单元测试(Unit):占比70%;接口测试(Service):占比20%;集成测试(UI):占比10%;
三、自动化测试最佳实践
对现阶段公司大部分团队来说,更符合实际测试模式是纺锤模型。新项目中,可能由于时限原因或者开发人员习惯问题,一开始并没有把单元测试准备得很完善;而某些遗留老项目,可能原本就没有多少单元测试。
在上述情况下,一般的做法是先将重心放在中间层的测试上,原因有以下两点:
第一,中间层投入产出比较高,可以实现较高的自动化率;
第二,可以帮助加强开发跟测试人员之间的协作,提高测试质量。这一层需要开发跟测试人员共同定义,因为开发知道内部实现的细节,测试掌握业务场景。
3.1 纺锤型向金字塔型过渡
当项目进行一段时间以后,各层测试占比有必要向理想型的金字塔型过渡,这时需要关注以下三个方面:
开发与测试互相传递能力;
全员关注产品设计跟代码的质量;
让用例逐步下沉,最后逐步过渡到理想型。
3.2 测试质量评估
关于度量,不要用单一的指标去评估测试和产品质量,比如用例通过率、代码覆盖率等都无法独立地评估产品质量。
评估测试质量时要关心以下几个方面:
第一是用例比例,即每一层的用例比例是多少。
第二是测试覆盖率。
第三是测试总运行时间,因为经过优化以后,总运行时间一定是越来越少。
第四是代码质量指标,反映代码的质量和整洁度。
四、自动化测试面临的挑战
引入自动化测试可以为团队带来很多好处,当然自动化测试也有其自身的缺点和挑战。面临的最大挑战就是变化,因为变化会导致测试用例运行失败,所以需要对自动化脚本不断debug。如何控制成本、降低成本是对自动化测试工具以及人员能力的挑战。
另一个值得注意的是,自动化测试不能完全代替人工测试,一定的人工探索测试也是必不可少的。我们一直在不懈努力和探索,本文为自动化测试最佳实践系列文章的第一篇,重点介绍了自动化测试的现状和金字塔模型,接下来的系列文章中会继续为大家介绍我们的自动化测试实践,包括自动化测试平台的核心功能、持续测试的方法与工具等。