前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Web 自动化:一种基于 Page Object 的实现及常见异常处理

Web 自动化:一种基于 Page Object 的实现及常见异常处理

原创
作者头像
腾讯移动品质中心TMQ
修改2017-06-30 16:59:47
2.5K1
修改2017-06-30 16:59:47
举报
文章被收录于专栏:腾讯移动品质中心TMQ的专栏

作者:mekhidu

团队:腾讯移动品质中心TMQ

前言

Selenium的使用本身十分容易,配置好环境后,即可选择自己熟悉的语言快速的编写脚本。花费力气引入设计模式增加首次构建难度,主要是为了以下两点:

1、减少维护成本。

Web产品往往界面变动频繁,如果每次更新后都需要花大量时间更新用例,自动化测试的收益大大降低。长期使用问题会越积越多,最后导致自动化方案破产。良好的设计模式能够减少重复代码,将元素操作与用例实现隔离开来,增加用例层的可读性,减少元素属性变化带来的测试用例重构工作,使得用例维护更加容易。

2、增加用例稳定性。

现在的Web前端存在大量AJAX与DOM元素操作,如果采用简单的面条代码编写用例,需要重复地去解决前端的AJAX等待和元素刷新等操作带来的StaleElementReference、NoSuchElement、NotClickable等异常。

一、Page Object设计模式简介

Page Object设计模式是Selenium官网推荐的一种自动化构建模式。PageObject设计模式对网页进行一个简单抽象,将每个页面设计成一个类,页面元素定位、元素操作、用户行为都被封装进对应的类。编写测试用例时不再直接操作页面元素,而是调用对应页面类的方法。使得测试人员在编写用例时能更多的关注业务逻辑,而不是页面结构与元素。

举个简单的例子,假设待测产品包含两个页面:登录页、个人中心。需要编写一个测试用例,实现用户登录并且点击签到按钮的过程。

用传统的线性方法实现时,用例逻辑、元素查找、元素locator等混在一起。如果是做冒烟测试或者简单页面的测试可以选择这种方式:

采用Page Object模式实现该用例的简要步骤如下:

第一步,为每个页面创建一个Class,页面Class内包含此页面元素的定位和行为:

第二步,调用创建的页面Class来编写用例:

虽然初始构建工作量更大,但是在产品变更频繁时,使用PageObject模式的优点明显:

1、测试用例的代码和页面元素操作的代码分离,用例可读性;

2、同一个元素的定位器不会出现在多个用例中,元素变更时只需要修改元素所在页面类;

3、登录的方法可以复用于多个用例中,如果产品登录流程发生变动,只需要修改登录页登录方法的实现。

为了在页面Class里更好的管理定位器和减少元素查找的代码量,Selenium提供了PageFactory类,使得我们在实现页面类时只需要用注解描述元素定位即可。调用元素的各个方法时,工厂类会自动根据定位器实时查找元素,在减少代码量的同时还能够帮忙避免DOM刷新带来的不稳定,详细使用见selenium官网。

二、Page Object基于控件的实现

既然PageObject设计模式这么棒,那为什么不直接拿来用呢?原因是在自动化工程的建设过程中,作者发现不同页面之间的DOM元素存在复用,页面并不是最小的UI单元,控件才是。这也是目前许多Web产品的特征,基于一套开源或者自研的前端控件库,页面结构由控件组成。同一控件的不同实例DOM结构类似,用户在页面上的操作可以看作是对各类控件动作的组合。

对这种类型的Web产品如果直接采用Page Object模式构建自动化测试,会导致在页面Class里重复对同一种控件的内部元素进行解析和操作,造成了大量重复代码并且加大了维护的难度。因此本次自动化测试工程的构建从控件出发,对每个控件的属性和方法进行封装,通过不同控件方法的组合来模拟用户操作,通过对用户操作的组合实现用例的自动化。如下图,自动化测试框架现在从下往上分为三层。

控件层,对前端所用控件在自动化工程中的抽象,继承自BaseConrol基类,基类中包含返回元素引用的方法getControl、查找子元素的方法getChildElement、等待元素加载的方法waitElementLoad等。派生的控件类包含各自特殊功能的实现,如小说目录包含翻页、按钮功能包含点击、导航栏包括后退等。

工具类层,包含两部分。

第一部分是一个控件查找类ControlFinder,可以根据XPath、CSS Selector等返回对应的控件。

第二部分是按照功能区划分的helper类,以本产品为例,按照找书、读书、个人中心等功能区创建了SearchHelper、ReadHelper、UserCenterHelper等工具类。这些类继承自BaseHelper,各个helper内通过对各种控件方法的组合对用户常见动作进行模拟。

用例层,继承自BaseStory,BaseStory内包含了用例执行前准备、用例结束后数据清理、失败截图、driver管理等功能。Story的划分按照产品用例类别进行划分,每个Story中包含多个用例,用例的编写依靠对工具层用户行为的组合。控件层和工具类层的实现在下一章结合具体问题给出。

基于这种模式,最后实现的用例如下:

三、提高测试稳定性

AJAX异步和DOM元素更新给Web自动化测试的稳定性带来了巨大的挑战,下面列举了常见的几个问题和它们在该模式下的解决办法。

1、查找元素时遇到NoSuchElementException

出现此问题一般是因为Selenium的查找操作在元素加载之前就已经结束。许多测试脚本在这里会选择用Thread.sleep()来等待元素加载,但是等待时间如果选大了浪费,选小了元素可能还没来的及加载。这种问题在此设计模式中可以用工具类ControlFinder集中解决,在根据定位器查找控件时,等待控件元素在页面出现,然后再返回对应的控件。

这里举的例子为每个控件都创建了一个查找方法。如果被测产品的控件提供返回控件名的方法,ControlFinder可以在查找到元素后,用javascript调用该方法返回控件名称,然后通过反射返回对应控件的实例。这样能实现一个查找方法查找多种控件。

2、StaleElementReference

这是Selenium测试脚本常见的异常,出现此问题的原因一般是所操作的DOM元素被刷新了。如下图的搜索页面的提示词,红框圈出来的提示词在页面中的层级一致,元素属性一致,但是从左图到右图,该提示词所在的DOM元素其实是被刷新过,两个看起来一样的元素在Selenium看来有着不一样的element id。就像两个人即使长得一样,但是身份证不一样,并不是同一个人。

现实现这样一个用例:

1)搜索“雪”,检查第一个提示词。

2)然后再输入“中”,检查第一个提示词。

问题写法如下:

上图代码在第二次调用hintWord.getText()时,DOM元素已经被刷新,hintWord所指向的DOM元素已经不是最初的那个元素了,因此会抛出异常。这类解决思路是,在输入“鹰”之后,重新查找一次该元素,于是有以下代码:

但是上面的代码运行过程中还是会有一定概率抛出

StaleElementReferenceException,抛出异常时的执行顺序如下图。脚本输入“中”之后,前端准备更新提示词,在更新完成之前第二次查找提示词元素的脚本已经执行了,这是hintWord还是指向ID=1的元素,然后前端完成DOM更新,测试脚本调用hintWord.getText()。因为此时ID=1的元素已经不在页面上了,所以程序出错。

下面看一下这个问题在该设计模式下的处理方法:

首先在控件基类中定义一个getControl()方法,此函数根据控件的定位器查找控件,并等待控件可见。

然后编写Label控件的类,Label控件包含一个检查文本的方法,该方法在默认等待时间内循环检查控件的文本。

1)如果元素查找和获取元素文本都发生在DOM刷新之前,那么获取的文本是刷新前文本,循环继续。

2)如果DOM刷新发生在元素查找和获取元素文本之间,则抛出异常。异常被处理,程序继续循环,下一次即可正常获取文本的值。

3)如果元素查找和获取元素文本都发生在DOM刷新之后,程序获取到最新值,检查通过。

4)如果DOM刷新超时,Assert不通过。

这样当DOM刷新后,测试程序马上获取到更新后的文本。如果超过规定的响应时间,也认为是待测产品异常,用例不通过。

下面是用自定义控件实现用例的代码,通过实时查找实现了控件变量的一次声明多处调用。

3、Element is not clickable

出现这个问题一般有三种原因:

1)该元素处于非点击状态

2)该元素被其它元素遮挡

3)该元素处于浏览器窗口外

为了规避第一种情况,在实现控件的点击方法时,应该先等待其变成可点击状态。

对于第二种情况,在浏览器上这种被遮挡的元素本来就不应该对其进行操作,应该尽量避免操作被遮盖的元素。

第三种情况是使用ChromeDriver时特有的异常,点击视野外的元素时有一定概率触发异常,官方傲娇的表示不修复此问题。为了提高这里的稳定性,在点击之前应该利用Selenium的Action移动到待点击元素。

综上,一个安全的点击事件应该长这样:

获取更多测试干货,请搜索微信公众号:腾讯移动品质中心TMQ!

版权所属,禁止转载!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档