随着软件复杂度的不断增加、更新频率的不断提高,单纯的手工测试已经显得力不从心,此时自动化测试应运而生。如果单从字面意思来说,会让人误以为自动化测试是用来代替手工测试的,但是在实际项目中,自动化测试往往是手工测试的补充,用于提高测试质量或效率。
从软件测试分层的理念来看,一般将软件测试自底向上分为单元测试、集成测试和系统测试3个阶段。这3个阶段可以映射到敏捷大师Mike Cohn提出的测试金字塔,它告诉我们越底层的软件测试活动越稳定、收益越大,而越上层的软件测试活动越不稳定、收益越小,因此应该将更多精力投入到底层软件测试活动中。这个结论放在自动化测试中同样适用。由于单元测试一般由开发人员来实施,因此测试团队在实施自动化测试的过程中通常不需要过于关注这一层。在实际项目中,集成测试一般主要体现为接口测试,那么对应到自动化测试中则应该实施自动化接口测试。而系统测试中最常见的就是基于界面的端到端测试,因此界面自动化测试必须模拟真实用户从界面发起对软件的使用,由于这种端到端测试的稳定性和执行速度很慢,从而导致实施成本很高。
从以上分析可以得出结论:自动化测试应该以接口自动化测试为主、界面自动化测试为辅。因此本文实际上是要探讨如何提高接口和界面自动化测试的效率。实施自动化测试的目的无非是提高测试质量或效率,但如果自动化测试本身的效率低下则会阻碍它提高测试效率。就好比你开车去几公里外的超市买菜,本着节省时间(提高效率)的目的,没想到却遇到严重堵车,导致在路上耽误了很长的时间,最后算下来还不如骑共享单车来得快。
关于自动化测试的效率,我将其归纳为3个方面,即建设效率、执行效率和维护效率。
- 建设效率
从没有自动化测试到有自动化测试,这个0到1的过程被称之为自动化测试的建设过程,如果这个建设过程很慢,可能直接导致自动化测试“胎死腹中”
- 执行效率
当自动化测试用例达到较大规模后,需要考虑自动化测试的执行效率,因为如果自动化测试不能及时反馈测试结果,则很难让人持续使用它。
- 维护效率
同样,当自动化测试用例达到较大规模后,自动化测试的维护效率变得至关重要,往往会出现自动化测试用例难以维护的情况,比如开发人员提交给测试人员一个新的软件版本,而测试人员需要修改大量自动化测试用例才能用于冒烟测试,从而促使测试人员放弃使用自动化测试来做冒烟测试,而直接使用手工测试来代替。
![](/qrcode.jpg)
提高建设效率
在自动化测试的建设过程中,往往有很多误解,最常见的有:
▲越简单越好:直接使用录制回放工具生成自动化测试用例,比如Badboy或Selenium IDE,前者用于接口自动化测试的脚本录制,后者用于界面自动化测试的脚本录制。录制后的脚本可直接或经过少量修改就可以用于自动化测试。
▲越灵活越好:这种观点一般来自技术宅,他们代码能力强,鄙视一切“拿来主义”,所有的东西都想自己重写一遍,这样可以针对当前所处公司的项目进行最大程度的灵活定制。
这是两种极端的声音,它们都不可取。越简单意味着不够灵活,比如测试数据与测试逻辑耦合在一起,修改测试数据就需要修改测试用例,显然是不可取的。而越灵活意味着越复杂,比如测试执行不使用现成的框架,想自己开发一个,那么就得考虑测试用例加载、测试用例执行、结果收集、报告生成等问题,增加了不必要的开发成本。
说到这,可以看出自动化测试的建设效率并不是越高越好,因为自动化测试的整体效率还受制于执行效率和维护效率,如果单纯采用“越简单越好”的方式来实施,那么势必会造成后期的维护成本增加,从而降低维护效率。我个人推崇的方案是以“越灵活越好”的方式为基础,根据实际项目进行权衡,以找到一个相对高效的自动化测试建设路径。以下举两个例子来说明。
案例1:某创业公司资产管理系统
迭代周期2周左右,对时效要求高。这种软件相信在大部分互联网公司很常见,它们往往需要迅速推出软件来占领市场。由于变更非常频繁,因此这种软件基本不具备做界面自动化测试的条件,甚至接口自动化测试也很难维持到一个较大的规模。这种情况下,我建议直接使用现成的自动化测试框架,并做好基本的分层和解耦即可。
案例2:某行业巨头基站管理系统
迭代周期6个月,对质量要求高。这种软件很明显是B端产品,开发该软件的公司由于是行业巨头,因此不需要着急占领市场,它更多的是想把产品质量做好。这种情况下,我建议扩大界面自动化测试的规模,对于自动化测试框架,可使用现成框架或对现成框架二次开发,甚至自研全新框架。
提高执行效率
在探讨提高自动化测试执行效率之前,首先来看看自动化测试是如何执行的,如下图所示是自动化测试执行的常见流程。
准备测试环境:自动化测试环境不管是独立的还是混用的(与手工测试环境混用),在执行测试用例之前准备测试环境是必须的。
准备测试数据:测试数据分两种,一种是静态测试数据,即在编写测试用例时就固定的测试数据;另一种是动态测试数据,即在测试用例执行时才能确定的测试数据。这里的准备测试数据是指前者,而后者被包含在了执行测试用例阶段。另外,这里的测试数据实际上包含了测试输入数据、元素控件值、配置数据等所有测试相关的数据。
选取测试用例:针对不同的测试场景需要选取不同的测试用例,比如冒烟测试和回归测试,它们选取的测试用例集显然是不同的。即使同一个测试场景的不同时期选取的测试用例集也可能不同,比如回归测试,在不同软件迭代版本中回归测试的范围往往也是有差异的。
执行测试用例:具体的测试用例执行过程,在已经准备好的测试环境和测试数据情况下,执行选取的测试用例。
分析测试结果:执行测试用例完成后,一般由人工来分析测试结果,这个过程需要将失败的测试用例进行分析定位,以判断是产生了缺陷还是测试用例自身的问题。
当自动化测试用例达到较大规模时,第4步执行测试用例显然是整个流程中最为耗时的部分,尤其是有外部不可控的异步任务(需要一直轮询结果)或大量的页面加载等。
那么如何提高执行效率呢?
▲使用并行执行:使用多线程来并行执行自动化测试用例将大幅度提高执行效率,减少执行时间。但是使用多线程需要考虑线程安全性,较好的实践是测试用例之间没有依赖关系,这个依赖关系包含逻辑依赖和数据依赖。
▲使用测试替身:测试替身用于代替真实的测试对象,比如常见的接口Mock对象,它用于代替不存在、不完整、不稳定或受限的依赖接口。
▲使用智能等待:在自动化测试用例的编写过程中,应该少用硬编码的线程休眠来达到等待的目的,比如在Selenium中,应该使用显式等待来智能匹配等待条件。
提高维护效率
首先来看一个例子,以下是一个简单的TestNG测试类:
如果仅从使用角度来讲,这个测试类中的两个测试方法没有任何问题,因为它们都能正常执行。但从维护的角度来讲,它们是不易维护的(维护效率低的),因为“操作a”和“操作b”中的逻辑可能会发生变化,一旦变化后需要测试用例维护者修改两次。假设测试用例的规模足够大,那么可能有很多地方调用了“操作a”和“操作b”,由此带来的维护工作量可想而知。另外,即使“操作a”和“操作b”中的逻辑不变,输入数据的变化也会迫使测试用例维护者修改测试用例。
那么如果提高维护效率呢?
▲分层
分层的目的在于将自动化测试分为不同的层次,这个层次是从抽象到具体的过程,以便在不同层次上进行维护。
公共层:自动化测试框架的框架代码、公共函数(方法)的封装,该部分代码与具体业务无关,适用于所有软件项目。这一层是最抽象的,一般由测试开发工程师或经验丰富的自动化测试工程师来维护。
业务层:业务函数(方法)的封装,该部分代码与具体业务有关,仅适用于当前软件项目。这一层需要根据实际情况来分配维护者。
测试用例层:具体的自动化测试用例,这一层是最具体的,一般由自动化测试工程师或具备一定代码能力的测试工程师来维护。
▲解耦
解耦的本质是将“变”与“不变”分开。当然,这里的“不变”是相对的。
变:大部分的测试数据被认为是变化的,测试数据包含了测试输入数据、元素控件值、配置数据等所有测试相关的数据。
不变:大部分的业务逻辑是可以在多个自动化测试用例之间共用的,比如登录逻辑、创建订单逻辑等。因此需要将这部分业务逻辑抽象出来放到业务层,以便大家使用和集中维护。
-End-
本文作者:卢家涛,精通自动化测试,负责过大型自动化测试项目的用例维护及整个公司自动化测试的实际项目落地。除了自动化测试,也擅长全栈测试开发,原创开源项目有testauto、WFT和IMS等。曾著有《全栈自动化测试实战——基于TestNG、HttpClient、Selenium和Appium》一书,并创办公众号“自动化测试理论和实战”,分享技术经验。
作者:卢家涛 编著
关键词:软件工程、开发项目管理、软件质量、软件测试及维护
适合人群:中高级测试工程师、 测试开发工程师
本书共12章,第1章首先以一个自动化测试用例为引子,接下来的10章对由此引申出的自动化测试中的多个热门专题,包括测试用例分层、数据驱动测试、关键字驱动测试、Page Object设计模式、等待、断言、测试报告、测试替身、并行执行、分布式执行和持续集成等进行了详细介绍,第12章以展望的形式对自动化测试平台以及容器化和人工智能技术在自动化测试中的应用做了简介。