软件自动化测试基础知识(下)
本章节讲解的是在软件测试中自动化测试的四个内容:
如何决定是否采用自动化测试
在软件自动化测试架构及步骤
软件测试的成本
自动化测试脚本处理出错的两种模式
一、如何决定是否采用自动化测试
既然“自动化测试不是银弹”,那么如何来选择自动化测试呢?
(1)适合采用自动化测试的场景
● 项目周期长,系统版本多
周期长的项目,特别是才用了敏捷开发模式或者DevOps,需要经常发布新的版本呈现给用户(据不完全统计,采用敏捷开发模式的企业一般在2-4周内发布一次版本,比如像BAT、TMD、eBay、Face Book等这些大型互联网企业一般版本的发布周期为一天2-4次),这样可以得到用户的及时反馈。在这种模式下,自动化测试就起到了非常关键的作用,每一次发布,起码要保证基本的功能没有缺陷,如果采用人工的方式几乎是完全不可能达到的。
● 需求变更不频繁
自动化测试最怕的就是需求变更,因为一旦需求做了变更,产品代码需要变化,相应的测试代码也需要进行变化。所以在需求变更不平凡的情况下,才建议采用自动化测试。
● 系统中测试对象可识别(协议可模拟)
作为基于GUI的测试,可以分为三步:“获取对象”“操作对象”和“断言”。所以被对象必须是可以被识别的。
作为基于接口的测试,可以分为三步:“组包”“发包”“收包”和“断言”。所以协议必须是可以模拟的。
● 手工测试无法完成的
有些测试时是手工测试无法实现的,比如前面提及的性能测试、强迫症测试等。
(2)不适合采用自动化测试的场景
● 项目周期短,需求变更大
对于短期的软件项目是不适合于做自动化测试的。一般业界有一个不成文的规定,如果一段测试脚本重复利用不超过五次,那么这样的产品最好不要采用自动化测试的方式。
● 在软件需求还没有稳定情况下
正如前面所说的,在软件需求还没有稳定情况下,软件变更肯定非常频繁,这个阶段下投入自动化测试,是得不偿失的。
● 没有明确的项目测试自动化计划、措施和管理
不了解自动化测试的原理、团队成员没有自动化测试的能力、不了解自己的产品是否适合自动化测试或者是否适合特定的自动化测试工具或者框架,建议不要实施自动化测试。
● 脚本维护量大
自动化测试包括前期投入和后期投入,在后期投入中,维护自动化测试脚本占主要的因素。如果估算到在产品开发后期,自动化测试脚本维护量会很大的时候,请慎重选用自动化测试。
● 对象无法识别(协议不可模拟)
对象无法识别的产品往往是采用了第三方控件的产品,做自动化测试,往往要理解代码中的一些细节,属于灰盒测试的范畴。又如前面所述,功能自动化测试步骤第一步就是识别对象,如果连对象都识别不了,自动化测试是无法进行的。
同样对于接口测试,协议无法通过工具模拟,也是无法实现的。
● 新特性
对新特性的测试主要目标是发现更多的缺陷,在AI辅助下的自动化测试还没有得到普及之前,最好采用人工参与比较多的探索式测试,而不要初期就采用自动化测试。另外即使是基于功能的自动化测试,也是经过了人的第一次手工测试以后完成书写自动化测试脚本的。
● 领导不支持
由于自动化测试是一个高投入的工作,高投入是否还会产生该回报,需要得到相关领导的决策。既要反对自动化测试神话论,也要反对自动化测试一无是处论,合理地使用自动化测试。
案例 1-1 项目何时介入自动化测试
在一个DevOps项目中,什么时候自动化测试介入比较好?请说出原因。
A)项目初期阶段
B)项目中期阶段
C)项目后期阶段
这个选择题应该选B),因为在项目初期,一般需求没有确定,所以不适合做自动化测试;而在项目后期,项目基本上处于结束状态,自动化测试在这个阶段介入也不是很合适。
案例 1-2 什么类型的功能适合做自动化
以下几个功能,哪些作为自动化测试用例比较好。
A)用户注册功能(字段尚未明确)
B)登录功能(需要验证码)
C)配货地址信息修改
D)登录用户修改自己的登录密码
这个选择题应该选C)和D)。对于A)由于字段尚未明确,肯定是不适合做自动化测试的,等字段明确后可以考虑;对于B)由于需要验证码,现在还很难实现自动化,但是业界正在通过图像识别的技术来研究对验证码识别从而来实现自动化测试。一般的做法是,让开发工程师在测试环境中,先把验证码功能隐藏,进行自动化测试,而在生产环境中把这些隐藏的代码打开。
二、软件自动化测试架构及步骤
(1)软件自动化测试架构
软件自动化测试架构如图1-5所示。
图1-5软件自动化测试架构
一般是这样组织软件自动化测试文件的。产品中所有的自动化测试用例放在一个目录下,这个目录下所有文件的总体叫做测试集,然后按照功能模块把不同的功能放在不同的测试文件中,在每个文件中按照子功能建立不同的类,在不同类种建立不同的函数,每一个函数对应相应的测试用例。现在大都数测试框架在测试用例(函数)前后、类(子功能)前后、文件(功能)前后提供初始化和结束函数以对相应级别进行操作。有些测试框架甚至提供在每一个测试用例中的步骤和整体测试集的前后提供初始化和结束函数。在测试框架中初始化和结束函数叫做装饰器,详情请参看本书第2章。其目录文件组织架构参见图1-6所示。
图1-6软件自动化测试文件组织架构
(2)基于GUI的自动化测试步骤
基于GUI的自动化测试步骤如图1-7所示。
图1-7基于GUI的自动化测试步骤
I.通过元素上的标签识别元素(比如在WEB上往往通过id、name、class、target、link、XPath和XSS来定位)。
II.对识别的对象进行操作(比如:输入、点击、双击、下拉等)。
III.如果测试未结束,回到第I.步。
IV.通过断言,判断测试是否达到预期结果。
(3)接口测试的自动化测试步骤
接口测试的自动化测试步骤如图1-8所示。
图1-8接口测试的自动化测试步骤
I.根据协议组包。
II.向服务器发包。
III.接受服务器返回的包。
IV.通过断言,判断测试是否达到预期结果。
三、软件测试成本
软件测试成本一般分为前期成本和后期成本。如图1-9所示。
图1-9软件测试成本
● 前期成本包括:开发语言/测试工具的学习、测试脚本的开发以及测试脚本的调试。
● 后期成本包括:测试脚本的维护,比如健壮性维护、根据需求变更的维护等。
根据有关部门的统计,后期成本往往要比前期成本高许多。降低后期成本最有效的方法是建立良好的易于维护的测试代码框架,比如现在许多企业都采用面向页面的或者面向业务流的测试脚本模式,就是更有效地解决后期成本的方法。作为开发能力不强的中小型软件开发团队,最好咨询相关的开发人员,尽可能在早起建立良好的测试脚本体系。
四、自动化测试脚本处理出错的两种模式
使用自动化测试框架书写自动化测试程序,判断测试是不是满足需求是通过断言的方式来实现的。但是在断言前面,程序的运行过程中也许会出现各种各样的问题,对于这些问题如何处理呢?一般采用两种方式。
● 遇到问题立即停止:如果在程序中不做任何处理,测试脚本遇到问题就立即停止。
● 遇到问题,记录问题,继续操作:如果在程序做了处理,当测试脚本遇到问题的时候,测试脚本记录问题到log文件中,继续操作。Python对于这种处理方式是这样的。
try:
…
except:
log.i(“error infomation”)
如果在try中的语句发现问题,被except捕获到,就把相应的结果输出到日志文件中。图1-10是LoadRunner对于上述两种方法的设置。
图1-10 LoadRunner对于发生错误处理的选择设置
在初始化函数主要的工作是为测试用例执行配置环境,比如加载相应的插件、打开对应的浏览器并且定位到开始的页面、配置测试用例所需的参数、打开文件或者建立数据库连接等;而结束函数主要工作是清理环境,保证下一个测试可以顺利进行,比如:关闭浏览器、恢复参数为默认值、关闭文件或者建立数据库连接等。请考虑如下这个案例。
产品默认数据库中不存在一个名为“Jerry”的用户信息。
● 登录模块测试用例。
1.初始化函数。
建立数据库连接。
插入一条用户数据,名为“Jerry”。
打开浏览器并定位到登录页面。
2.测试函数。
用初始化函数中建立的用户数据登录。
验证登录是否成功。
3.结束函数。
登出页面。
关闭浏览器。
删除建立的用户。
关闭数据库连接。
● 注册模块测试用例。
1.初始化函数。
打开浏览器并定位到注册页面。
2.测试函数。
用名为“Jerry”的用户名注册。
验证注册是否成功。
3.结束函数。
关闭浏览器。
建立数据库连接。
删除注册成功的“Jerry”的用户
关闭数据库连接。
比如先执行登录测试用例,在运行到“用初始化函数中建立的用户数据登录”的时候出现了错误,测试代码被中断,测试程序不会执行结束函数中的“删除注册成功的‘Jerry’的用户”。接下来执行注册模块测试用例,由于“Jerry”没有清除,所以测试会告诉类似“注册失败,系统中存在名为Jerry的用户”的消息。
再如先执行注册测试用例,在运行到“验证注册是否成功”的时候出现了错误,测试代码被中断,测试程序不会执行结束函数中的“删除建立的用户”。接下来执行登录模块测试用例,由于“Jerry”没有清除,所以在初始化的时候会建立2条名为“Jerry”的用户,显然是违背产品业务逻辑的。
所以必须把登录测试用例改造为。
● 登录模块测试用例。
1.初始化函数。
建立数据库连接。
判断系统中是否存在名为“Jerry”的用户。
如果没有,插入一条用户数据,名为“Jerry”。
打开浏览器并定位到登录页面。
2.测试函数。
用初始化函数中建立的用户数据登录。
验证登录是否成功。
3.结束函数。
登出页面。
关闭浏览器。
删除建立的用户。
关闭数据库连接。
注册测试用例改造为
● 注册模块测试用例。
1.初始化函数。
打开浏览器并定位到注册页面。
建立数据库连接。
2.测试函数。
判断系统中是否存在名为“Jerry”的用户。
如果没有,插入一条用户数据,名为“Jerry”。
用名为“Jerry”的用户名注册。
验证注册是否成功。
3.结束函数。
关闭浏览器。
删除注册成功的“Jerry”的用户
关闭数据库连接。
这样就可以解决问题了。