注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭州 QA Team

务实 专注 分享 做有态度的QA

 
 
 
 
 

日志

 
 

Web自动化框架搭建【上】  

来自尘泥   2012-02-27 20:01:31|  分类: 自动化测试 |举报 |字号 订阅

  下载LOFTER 我的照片书  |

引子

2011年初来公司实习的时候,接的第一份活就是维护UI自动化用例,从此开始我轰轰烈烈的Tester生涯,此处省略十万字。。。

 

经历第一代UI自动化的没落,DWR接口测试的兴起,以及直接参与项目组的功能测试,最终又回到了一年前的原点。

 

思考良多,苦逼地推出了第二代UI自动化框架,大名Dagger

 

废话少说,先讲技术选型

由于历史传统,Selenium2.0成为不二选择,Selenium2.0Selenium1.0WebDriver的合体,新框架Dagger是以WebDriver为基础。

 

再讲设计思想和定位

新框架之所以取名Dagger(匕首),就是希望它和匕首一样轻便灵巧,框架专注于实现各种Web操作的封装。其他的外围,如数据库连接,分布式执行,持续集成等则根据情况添加,将开发,维护,使用,分析用例的成本尽可能降低。

 

打个比方,匕首绑在木棍上就是长矛,装在步枪上就是刺刀,可以随机应变。因此,Dagger是如此之小,小到核心类只有3个,架包2个。

 

框架小巧方便,则可以把主要精力放在用例的实现和组织上,使用例尽量贴近业务。

怎样写用例,怎样封装xpath,怎样组织用例,才可以使写用例和维护用例成本最低?不仅仅是技术问题,更多的是实践经验的积累。

 

抛砖引玉,关于UI自动化的一些设想

一次性用例,主要用于验证功能是否正常上线;

SeleniumIDE,是Selenium自带的自动化录制工具,支持将录制用例直接输出为JAVA代码。充分掌握这一工具后,可以大幅提高写用例的效率;

一个用例就是一个类,内含所须的元素定位Xpath和各种驱动数据;

         优势:不同的人同时写用例不会互相干扰,责任清晰明确。

         缺点:潜在的维护成本。

责任人制度(很多时候用例的成效上不去,是因为用例挂了以后没有责任人及时分析,反馈维护);

核心的,稳定的功能,用例写的规范些,便于阅读和维护;

普通的,易变的功能,用例写的随便些,挂了就重写一个;

UI自动化用于回归,要像脚本,不要像代码,就是手动回归的脚本化;

用例傻瓜化,容易写容易读容易维护;

一个用例一组专用账号,方便隔离和数据准备,也便于后续的用例分布式并行执行;

最关键的一点,自动化必须贴合业务!

 

下面上代码(节约版面,部分节选)

架包只有2个:

         selenium-server-standalone-2.18.0.jar

         testng-6.3.1.jar


框架核心类3个:

BrowserEmulator               浏览器类,一个浏览器的抽象

GlobalSettings                   所有的配置项都统一放在这里

PageElement                     页面元素类

 

先讲BrowserEmulator

宾老板曾问我,为啥要把Selenium再封装一层,变成BrowserEmulator这个类?宾老板永远是那么的犀利,吓得我颇心虚。幸好我是有备而来,理由有三:

1.       Selenium本身提供了大量API,这是好事吗?我觉得不是,功能强大是好,但里面95%API都不是常用的,徒增烦恼罢了,因此加一层封装;

2.       Selenium2.0Webdriver)有不少Bug和缺陷,谁用谁知道!因此要加一层封装,补全之。

3.       加了一层封装以后,哪怕Selenium大变样甚至以后不再用Selenium了,也可以保证BrowserEmulator对外提供接口的稳定性。

 

代码如下,穿插说明。

/**

 * Selenium2.0二次封装

 * @author 尘泥

 */

public class BrowserEmulator {

    WebDriver BrowserCore;

    WebDriverBackedSelenium Browser;

这里有一个三层体系,最里面的是WebDriver,外面包一层WebDriverBackedSelenium,最后再包一层用户直接接触的BrowserEmulator。看官可以在下文看到有些API是基于WebDriver实现的,有些则是基于WebDriverBackedSelenium,看起来很囧,不是么?理论上,所有的Web操作只用WebDriver相关的API就可以实现,但是,亲,要自己写代码实现哦!很麻烦,考虑到这一点,Selenium2.0本身就提供WebDriverBackedSelenium类,把WebDriver类包装一层,并对外提供大量类似于Selenium1.0API,用起来很爽,是不是?不是,因为WebDriverBackedSelenium模拟了Selenium1.0API,但模拟比较蹩脚,有些APIBug,有些则根本没实现。所以,还得回过来靠WebDriver实现。一会要用WebDriverBackedSelenium,一会要用WebDriver,可以想见,如果不在最外面封装一层BrowserEmulator,用户使用起来会是何等的苦逼!?当然了,熟练的自动化测试工程师不在此例。

     ChromeDriverService ChromeServer;

要使用Chrome浏览器的话,还必须起一个server。不过即便要多起一个serverchromedriver还是比firefoxdriver启动快得多!

    JavascriptExecutor js;

加个JS执行器,有些东西还得靠JS直接来实现,详见下文。

       public BrowserEmulator() {

             chooseBrowserCoreType(GlobalSettings.BrowserCoreType);

根据配置参数选择浏览器类型,目前只支持FFdriverChromedriver,理论上,还可以支持IEdriverhtmlUnitdriver,但实际上,虽然它们都是实现了webdriver接口,但是实现的具体代码各不相同,导致一些Web操作在不同driver之间有兼容性问题。具体问题,下文将有涉及。

Browser = new WebDriverBackedSelenium(BrowserCore, "www.163.com");

Browser.setSpeed(GlobalSettings.StepInterval);  

// TODO 这里Selenium2.0存在BugsetSpeed()实际上无法设置运行速度。

       Browser.setTimeout(GlobalSettings.Timeout);

       js = (JavascriptExecutor) BrowserCore;

    }

     /**

     * iframe中输入文本

     * @param locator Xpath Of Frame

     * @param Text

     */

这个方法目前只支持FFchrome下不行,解决中。。。

    public void typeInFrame(String locator, String Text) {

 

       pause();

       waitForElementPresent(locator);

 

       // 进入指定iframe

       WebElement myframe = BrowserCore.findElement(By.xpath(locator));

       BrowserCore.switchTo().frame(myframe);

      

       // 进入编辑节点

       WebElement editable = BrowserCore.switchTo().activeElement();

       editable.sendKeys(Text);

      

       // 返回

       BrowserCore.switchTo().defaultContent();

    }

   

    /**

     * Robot敲击键盘

     * @param KeyCode

     */

出于安全性考虑,有些Web操作要求监听“真正的”键盘事件,这种情况应该也是比较常见的。所以这里使用java原生提供的Robot实现模拟键盘事件。而且键盘可以帮我们解决很多问题,比如,我按一下F5就可以实现页面刷新,那就不须要额外再为刷新页面写一个API了,又可以使代码简洁一些了。很多时候不能依赖框架提供这样那样几乎万能的API,其实自己完全可以想办法绕过去的。

    public void pressKeyboard(int KeyCode) {

 

       pause();

      

       Robot rb = null;

       try {

           rb = new Robot();

       } catch (AWTException e) {

           e.printStackTrace();

       }

      

       rb.keyPress(KeyCode);       // 按下按键

       rb.delay(100);              // 保持100毫秒

       rb.keyRelease(KeyCode);     // 释放按键

 

    }

   

    /**

     * Robot控制鼠标

     * @param positionX

     * @param positionY

     * @param KeyCode

     */

原理同上一个API

这个API主要是为Flash自动化准备的。处于安全性的考虑,如果Flash操作将导致页面离开这个Flash or 会有表单提交之类的,那么Flash安全框架会强制要求这一次click必须是“真实的”鼠标点击。

    public void pressMouse(int positionX, int positionY, int KeyCode) {

    }

   

    

  评论这张
 
阅读(6494)| 评论(9)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016