Selenium在电话自动拨测系统中的应用
2021-10-28马天鸣
马天鸣,梁 琛
(1.上海工程技术大学 电子电气工程学院,上海 201620; 2.电信科学技术第一研究所有限公司,上海 200032)
0 引 言
在项目的开发过程中,新版本的连续发布使回归测试的需求更为频繁,在项目周期长,模块功能复杂的情况下,采用手工方式对系统功能进行多次重复的验证时,会消耗大量时间,增加测试成本。因此,选择正确的回归测试策略来改进测试的效率和有效性是很有必要的。使用自动化测试[1-3]的方式来进行回归测试,可以进行大规模、长时间和多周期的测试,既减少测试人员的工作量,又保证了测试的效率和准确性。
为了实现全国各局之间、局与各电信运营商网络之间的通信畅通,实时监测全网通断情况,及时、准确定位故障线路,对全网设备、资源优化提供科学依据等运营目标,迫切需要建设一套覆盖全网的电话自动拨测系统。
根据电话自动拨测系统需求变动不频繁、项目周期长以及系统界面稳定、变动少的特点,引入UI自动化测试来达到扩大测试覆盖率,降低回归测试成本的效果。
Selenium[4-8]是一个主要用于web应用程序自动化测试[9]的工具集合,最初是为网站自动化测试而开发的[10],它支持各种主流浏览器和多种编程语言,可以跨平台使用。该工具能模拟用户操作,在浏览器中直接运行,拥有足够好的用户体验[11],其开源优势以及功能特点符合电话自动拨测系统对于自动化测试工具的要求。
1 Selenium自动化测试的相关工作
1.1 电话自动拨测系统的介绍
电话自动拨测系统是B/S(浏览器/服务器)架构的系统,由统计分析、端局状态、端局管理、号码管理、拨测管理和系统管理六个模块组成,如图1所示。
其中,登录是进入系统的前提,端局管理和号码管理两个模块需要对大量的省市端局和号码进行增加、删除、修改、关联等操作,系统管理则需要添加各端局的登录用户、配置对应的权限,步骤重复繁琐,仅以手工的方式对这部分功能进行测试会消耗大量的时间和精力,增加测试人员的负担。故需要引入适合web应用程序的自动化工具对系统进行回归测试,从而提高测试效率。
1.2 Selenium概述
Selenium是一种基于浏览器的自动化测试工具,提供了一种跨平台、跨浏览器的端到端web自动化解决方案。Selenium支持主流的浏览器,包括Firefox、IE、Chrome、Safari和Opera等,它可以模拟使用者与浏览器之间的交互,如访问网站、点击链接、填写表单、浏览网页等。Selenium前后共经历了三个版本,分别是Selenium1.0、Selenium2.0和Selenium3.0,现使用最新版本3.0来做测试,Selenium3.0主要包括三个部分:Selenium IDE、Selenium WebDriver 和Selenium Grid。
Selenium IDE作为浏览器Mozilla Firefox的插件,不需要任何编程逻辑来编写测试脚本,它通过与浏览器的交互可以进行录制和回放,并能把录制的操作以多种编程语言的形式导出测试用例。
Selenium WebDriver提供了web自动化所需的API(应用程序接口),主要用作浏览器控制、页面元素选择和调试。使用Selenium WebDriver前要选择一种语言来编写自动化脚本且需要由selenium client library支持。
Selenium Grid提供了在不同浏览器上运行Selenium的能力,它的作用是分布式执行测试,可以控制多台机器以及多个浏览器执行测试用例。在测试用例较多的情况下,通过Selenium Grid可以提高测试效率。
1.3 python的优势
python是一门被广泛应用的高级编程语言,它语法简单、简洁易懂、框架复用性高、可移植性强,并且提供了大量的内置库、函数以及用户编写的第三方库,众多开源的科学计算软件包都提供了python的调用接口[12],从而可以容易地实现一些复杂的功能。python支持Selenium client library,既可以使用C/C++进行扩展,又能嵌入其他编程语言中,故选择python来编写自动化测试脚本。
1.4 Selenium自动化测试流程
Selenium的测试过程分为六个步骤,分别是制定测试计划、编写测试脚本、优化测试脚本、执行测试脚本、生成测试报告和邮件发送报告,如图2所示。
图2 Selenium自动化测试过程
1.4.1 制定测试计划
自动化项目的测试计划做得越详细,后期就越能按部就班地去执行,测试的成功率也就越高。对于系统而言,并非所有的功能点都适合使用自动化来进行回归测试,因此需要罗列所有符合Selenium测试条件的模块并对其功能点进行细化来设计测试用例,然后再实施后面五个步骤。
1.4.2 编写测试脚本
单元测试框架是编写自动化测试用例的基础[4]。unittest一般称为PyUnit,是从Java程序中广泛应用的JUnit启发而来的,可以使用unittest为任何项目创建全面的测试套件,unittest也是python中用来测试各种标准类库模块的[13]。现使用unittest单元测试框架来创建基于python的Selenium Webdriver测试脚本。unittest适用于web自动化测试用例的开发和执行,它可以用来组织和执行系统各模块的测试用例。
1.4.3 优化测试脚本
编写的脚本只包含元素定位和页面操作,没有校验测试用例中预期结果和程序返回的实际结果是否一致,因此需要对脚本进行优化,通过断言的方式来判定测试用例执行成功与否,如等价校验、逻辑校验和异常校验等。
1.4.4 执行测试脚本
测试脚本是以py为后缀的文件,在代码编辑器中运行当前文件,脚本便自动开始执行,Chrome浏览器立即弹出并按测试用例中的步骤依次执行,在结束时浏览器的窗口会自动进行关闭。
1.4.5 生成测试报告
使用unittest的拓展HTMLTestRunner生成格式友好的HTML测试报告,既能获取测试结果的概况,又能深入查看报告的细节。
1.4.6 邮件发送报告
以邮件附件的形式自动发送测试报告至相关技术人员的邮箱,这样能让他们及时了解系统缺陷的详细情况,有助于其后续工作的安排和开展。
2 Selenium测试的实例分析
2.1 制定测试计划
电话自动拨测系统中的系统管理、端局管理和号码管理分别牵涉到大量的端局用户、省市端局和拨测号码,用手动测试的方法进行重复的操作会消耗不少时间,而且降低了测试人员对于工作的积极性,使用Selenium工具对这三个模块中部分适合自动化测试的功能点进行回归测试,比如对拨测号码以及端局用户信息的新增,删除和修改等,这样可以减轻重复操作的负担,从而提高测试人员的工作积极性。
系统登录虽然不在系统管理、端局管理和号码管理三个模块的范围内,但由于操作任何一个模块都无法逾越这个步骤,因此该部分也纳入了自动化测试的范围。
2.2 编写测试脚本
2.2.1 系统登陆验证码
登录电话自动拨测系统的前提是输入正确的用户名、密码和由四个随机数字组成的验证码,用户名和密码是固定的,验证码则是随机生成的,需要正确识别才能进行后续操作,系统登录框如图3所示。
图3 登录框的显示
主要有四个方法来解决通过验证码的问题:(1)去掉验证码部分的代码;(2)使用一个万能验证码;(3)通过cookie直接登录系统,从而避开验证码这一步骤;(4)识别验证码中的数字并登录系统。第一种方法去掉验证环节会给系统带来安全风险,第二种方法则需要通过开发的协助才能完成,第三种方法不能对验证码进行自动化测试,因此只有最后一种才是安全,可行的方法。
要识别验证码首先要对数字区域进行截取,webdriver能对浏览器页面进行截图,但是整个浏览器页面过大,需要具体定位到验证码图片的所在位置。通过验证码的标签id定位到该标签所在页面的像素位置,再获取标签大小,确定图片的宽和高,从而获得验证码的位置和大小。在截取验证码图片后,使之转化成灰度图并增强它的饱和度,此时保存后的图片如图4所示。
图4 处理后的验证码图片
从图4可以看出,此时验证码的辨识度比较高,通过把图片中的内容转化为字符串的操作,成功地辨识出验证码中的数字,使得系统登录的整个过程得以自动完成。
2.2.2 单元测试框架
单元测试是一项对技术要求很高的工作,只有白盒测试人员和软件开发人员才能胜任,但用单元测试框架做单元测试却十分简单,而且单元测试框架不仅可以用来做单元测试,还适用于不同类型的自动化测试[14]。
单元测试框架是构建自动化测试用例的基础,在python中有多种单元测试框架,如unittest、doctest、pytest和nose等,电话自动拨测系统使用的是unittest,它可以为任何项目创建全面的测试套件,主要由Test Case、Test Suite、Test Runner和Test Fixture四个核心组件构成。在执行Test Suite(测试套件)后,unittest在命令行会输出对应的测试结果,使用unittest的拓展HTMLTestRunner可以进一步生成Test Report(测试报告),如图5所示。
图5 unittest单元测试框架
(1)Test Case[15-18](测试用例)。一个测试用例是在unittest中执行测试的最小单元,它通过assert方法来验证一组特定的操作和输入以后得到的具体响应。unittest提供了TestCase基类,可以用来创建测试用例。
(2)Test Suite(测试套件)。一个测试套件是多个测试或测试用例的集合,是针对被测程序的对应的功能和模块创建的一组测试,一个测试套件内的测试用例将一起执行。
(3)Test Runner(测试执行器)。测试执行器负责测试执行调度并且生成测试结果给用户。测试执行器可以使用图形界面、文本界面或者特定的返回值来展示测试执行结果。
(4)Test Fixture(测试夹具)。通过使用测试夹具,可以定义在单个或多个测试执行之前的准备工作和测试执行之后的清理工作。
(5)Test Report(测试报告)。测试报告用来展示所有执行用例的成功或者失败状态的汇总,执行失败的测试步骤的预期结果与实际结果,还有整体运行状况和运行时间的汇总。
2.2.3 页面定位元素
页面元素都是由HTML代码组成的,它们之间有层级地组织起来,每个元素有不同的标签名和属性值,WebDriver就是根据这些信息来定位元素的。Selenium主要有id、name、tag、class、link_text、partial link、XPath、CSS_selector八种元素定位的方法,这些方法根据一定的标准取查找元素,如果元素被正常定位,那么WebElement实例返回,否则抛出NoSuchElementException的异常。
电话自动拨测系统主要使用id、name和class属性来查找元素,这三种方式是最为普遍和快捷的,当上述方法无法生效时,使用XPath的方式可以灵活地运用绝对或相对路径来进行定位。
基于元素id的定位方法是通过查找Web页面上的元素id值来获取元素,比较简单,适合Web元素id固定的情况来使用,对于动态分配Web元素id的情况不能使用[11]。由于页面中元素的id是唯一的,因此通过id定位元素是最佳方法。
基于元素name的定位方法是另一种常见的查找元素的方式,可以通过匹配name的值来定位一个或者一组元素,如果匹配成功则返回查找的元素,匹配失败则抛出异常。
基于元素class的定位方法用来关联css中定义的属性,class可以指定元素的类名,其用法和id、name相类似。
基于元素XPath的定位方法是通过元素的路径来完成对元素的查找,XPath是XML路径语言,可以用来定位XML文档中元素的位置。Xpath分两种定位方法,一种是用绝对/相对路径来定位,另一种是使用元素属性来进行定位。
2.2.4 操作页面元素
Webdriver提供很多用来与浏览器交互的功能和设置,可以通过使用Webdriver的功能和方法来实现与浏览器窗口、警告、框架和弹出窗口的交互。自动化过程中与页面元素进行交互的方法都是由WebElement接口提供的,页面元素包含文本框、文本域、按钮、单选框、多选框和下拉列表等。
WebElement提供了一些功能和方法来实现与网页元素的交互,WebElement的功能如size(获取元素大小)、tage_name(获取元素的标签名称)和text(获取元素的文本值)等,方法如clear(清除文本)、send_keys(*value)模拟按键输入和click()(单击元素)等。WebElement与各种HTML控件的自动化交互,例如在输入框内写入文本、单击一个按钮和选择单复选框等。
2.2.5 页面元素等待
当没有定位到标签元素时,除了找错标签这个原因以外,还有一种可能就是标签由于网速等因素没有及时加载出来,直接获取会导致程序运行时报错,因此需要设置线程等待,Selenium提供了两种等待机制:隐式等待和显式等待。
隐式等待对于解决网络延迟或者利用Ajax动态加载元素所导致的程序响应时间不一致,是非常有效的,WebDriver类提供了implicitly_wait()方法来设置超时时间;显式等待可以只作用于仅有同步需求的测试用例,WebDriver提供了WebDriverWait类和expected_conditions类来实现显式等待[13]。
在处理同步问题上,显式等待的可操控性更佳,处理方式更灵活,故在电话自动拨测系统脚本的编写中使用显式等待的机制。
2.2.6 控制浏览器
浏览器的工具栏中一般都有前进、后退以及刷新的按钮,这些功能比较实用,在网页操作中经常会用到,Selenium Webdriver提供了这些操作浏览器的方法。
浏览器全屏模式可以用maxmize_window()的方法来实现,该方法无需设置参数;当想要让浏览器以某种特定的大小运行时,可以用set_window_size()的方法来设置浏览器的窗口大小。
Webdriver提供了forward(),back()和refresh()来模拟浏览器前进、后退以及刷新/重新加载的按键功能。
2.3 优化测试脚本
测试脚本中验证实际和预期结果是否一致是很重要的,unittest的TestCase类提供了很多实用的方法来校验预期结果与程序返回的实际结果是否一致,如assertEqual/assertNotEqual、assertTrue/assertFalse、assertIn/assertNotIn等,这些方法要求必须满足某些条件才能继续执行接下来的测试。如果给定的断言通过了,下面的测试代码则被执行,否则将会导致测试立即停止并且给出异常信息。
2.4 生成测试脚本
执行测试套件后,unittest在命令行输出测试结果,但是给相关技术人员发送命令行日志并不是一个明智的选择,生成一个包含所有用例执行情况的测试报告是很有必要的。unittest没有相应的内置模块能创建格式友好的测试报告,可以通过使用unittest的拓展HTMLTestRunner来实现,脚本生成的测试报告如图6所示。
图6 HTML测试报告
测试报告为HTML文件,可以用浏览器进行读取,它包含测试开始时间、持续时长、状态统计以及每个测试用例执行结果的详细描述。图6为系统管理、端局管理和号码管理三个模块选取部分用例所生成的测试报告,其中执行失败的用例可以通过展开Detail来对问题进行具体的定位和分析。
图7 邮件自动发送测试报告
2.5 邮件自动发送测试报告
以邮件的形式自动发送测试报告是电话自动拨测系统的重要需求之一,当测试脚本执行完成以后,便会自动向项目相关人员的邮箱发送测试报告。yagmail是python的一个第三方库,通过使用yagmail能以比较简单的方法来实现自动发送邮件的功能。在发送邮件时,除了填写主题和正文外,还可以增加抄送人和添加附件等。
由于HTMLTestRunner报告在展示时引用了Bootstrap样式库,当作为正文写在邮件中时,会导致样式丢失,所以作为附件发送更为合适,如图7所示。
3 结束语
为减少手工测试工作量,提高测试效率,使用Selenium自动化测试工具对拨测系统中三个主要模块进行回归测试。测试结果表明,该方法可以模拟手工操作反复地执行并生成直观、易于定位bug的HTML测试报告,最后以邮件附件形式每天定时发送给相关技术人员。相比手工测试,此方法节省了重复执行测试用例的时间,提高了测试效率,为开发能尽早修复缺陷,相关人员能及时了解测试情况提供了便利。