深入理解基于selenium的二次开发

时间:2022-12-25 21:23:44

对于做web端自动化测试的人来说,可能接触selenium比QTP还要多,但是我们在做基于selenium的二次开发的时候,经常会说到二次开发是为了易于维护,很多人可能不懂得维护的价值是什么,和到底要维护什么。今天专门写一篇关于二次开发的文章,希望能够帮到有需要做二次开发的人。 
     二次开发也就是我们常说的封装selenium,或者做框架。但是一个框架要包含丰富的类和方法。要有一套完整的体系来帮助我们进行封装。可以说框架的设计思想就是整个框架的灵魂,如果设计思想很正确也就意味着这个框架成功了一半,剩下的就是我们怎么样用程序实现这个思想,在开发的过程中我们也许会用到一些设计模式和引用一些开源框架。这些只是一个开发人员或者程序设计者的基本素质。至于如果把selenium能够有效的封装和一些基本思想,我们来详细的了解一下。 
     在这篇文章里面只针对selenium的webdriver来进行讨论,我们不再对rc做任何的解释和说明。我们都知道webdriver的使用过程中,贯穿始终的就是一个driver, 并且这个driver代表了一个浏览器的当前窗口,我们进行操作的过程中只是进行当前窗口的操作,也就是最这个current window进行的一系列的操作,如果我们需要对打开的新的window来进行操作的话,我们需要switchTo,包括操作frame,当然整个流程下的操作确实让我们觉得不是很难编写,但是我们编写脚本的过程中需要用到的一些辅助功能可能就会很难的编写,比如最大化浏览器,视角移动到操作的元素等等,这个过程一次编写我们可以做到,但是反复的编写的话肯定是一个让人很头疼的过程,所以这个时候我们要去封装一些常用的方法,我们有了做一个比较完整的框架的想法,但是我们忽然又意识到了,这样的话,我们需要把driver封装起来,因为整个测试的case都是针对的这个driver,并且只有一个driver,这样子的话我们不允许创造多个的driver,也就意味着我们要把自己编写的小工具类和driver联系起来,并且我们的测试用例case类也需要调用这个driver,其实很简单,我们可以用注入的方式来做,把driver当成tools类的一个属性值,然后注入到我们的case类中,也可以通过set的方法来进行操作。有了这些基础,我们可以防止无限的编写重复的方法,这样我们有了自己的工具类。如果说这就是框架的话,就会显得非常的肤浅,因为我们写的这些方法根本没有任何逻辑可言,只是把需要的方法统统的堆到了一起,所以这个时候我们需要想想用到某些方法来进行分一下层次。

Page类和Window类:

PageObject模式我们都知道,就是把资源都放入到page类里面,然后再编写逻辑类。这样的话就可以无限的复用这些资源,这只是笼统的讲了一下设计的思想,至于PageObject到底怎么去实现这些设计呢?我们从webDriver的使用开始入手。webdriver是先从定义浏览器开始的。WebDriver driver = new FirefoxDriver(); 这样我们就定义了一个firefox的浏览器,但是自动化的过程不可能只允许我们把定义浏览器的操作放在框架代码里面,那样的硬编码方式使我们的case不存在可移植性了,如果进行兼容性测试的话,维护起来对这些case的修改量是比较大的,这种硬编码方式是我们不能够进行大量维护的,所以我们需要把定义浏览器的过程完全放在case类里面,就是在我们写测试用例的时候再去编写到底用什么浏览器,防止在编写框架的时候硬编码的形式把浏览器写死在了框架里面。做到多浏览器的可维护性,对于我们进行兼容测试也有一定的帮助,这样的话我们需要对浏览器的选择部分要进行一定的编码设计,来完成浏览器的可选择性。在我们定义完了浏览器之后,这个时候我们也许觉得就是开始查找元素了,但是在这个driver的基础上我们应该发现其实这个时候driver代表的整个页面的操作。但是在页面的操作基础上我们应该意识到还有一个级别的操作,那就是window的操作,就是针对浏览器自身的操作。包括一些基本的返回,向前,最大化,最小化,或者移动到制定元素的位置,调用js等等等,这些方法的级别是出于window级别的,和页面无关的。所以我们应该把这些所有的方法都封装到单独的一个层次中,我们暂且称之为window包中,刚才的浏览器的选择的所有方法我们放browser包中。这样我们设计出了两个层次。下面的设计该如何进行呢?我们知道pageObject的思想是把资源都放入到我们定义的page类里面,所以这个时候我们需要思考了,我们如何设计这里的page类呢?按照pageObject的思想来看,page类应该是我们自己编写的,那样我们的框架是不是就可以放弃编写page类了呢?直接封装一些通用的方法?显然是不对的,对于页面html源码操作的过程中,我们烦透了这些元素查找的硬编码方式,在一个case里面或者两个case里面反复的调用编写是让人头疼的一件事情,所以我们可以把所有的单页面看做一个层次,里面和PageObject的思想一样,就是放入了通用的方法,但是它存在的意义不只是这样简单,因为我们操作的过程中需要涉及到frame。并且页面和页面之间涉及到不同window之间的切换,所以如何协调window和page之间的关系成为了我们需要注意的难点和重点,我们知道webdriver里面有一个方法叫做getWindowHandlers,这个方法可以获得所有的句柄,我们想设计这个page类那么意味着我们需要去完美的配合window类,他们之间唯一的关联就是这个方法,所以我们可以设计一个概念,叫做页面集合,在创建window对象的时候我们就会自动的出现一个页面集合器,它的功能就是管理所有的在操作过程中打开的页面。并且能够指定一个特殊的page,就是当前页面。也就是webdriver中的driver对象,因为它一直都是针对当前页面编程的。那样我们的window类里面就存在了两个属性,一个收集器,一个当前页。这样我们在window的级别上就能够完全操作page类了,这样我们在case类设计的时候,只需要通过window类的级别进行编码就可以了,完全可以把page类当作一种资源来处理,我们所有需要的东西都是通过page来获取的。page类的设计中我们一定要编写通用的方法。比如获取title等等等,最主要的一点就是要进行frame的处理操作,我们如何把frame完美的结合在page里面呢?我们在普通的webdriver脚本编写过程中可能反反复复的switchTo的方法让我们很恼火,并且很难让我们理解这些脚本到底是想表达什么意思呢?所以我们需要进行对page进行层次上的小分级,就是把page类再分为一个frame的类和一个模块的类,因为一个大型页面里面,通用的结构和模块是很多的。我们单独的定义一个模块类,可以让这些相同的结构复用在里面的方法。定义frame类主要是处理把定位到frame的操作从case类中脱离出来,我们编写到page类里面或者frame类里面,提供一种方式或者方法来进行frame的定位就可以了,简单实用,并且简化case类的编写,毕竟case类并不是由设计者来编写,尽量做到最简化。当然我们可以成这整个层次都是page类,放在page包里面。

Element类:

Element类就是我们常用的driver.findElement()的那种形式,就是元素类,什么是元素类呢?元素就是我们需要定位的那些东西,我们在操作过程中很难知道一个findElement到底查找的是什么,因为所有的标签形式都是通过id或者各种各样的定位方式来实现的。这个时候我们需要把各种各样的findElement都统统的放在一起,造成的脚本难以理解让后续接手的脚本开发人员可能头疼不已,所以我们可以做一些简单的加工。当然我们还要做的一个最大的工作就是元素查找的封装。Element和Page类如何关联起来。我们知道page和webElement的关联就是一个driver.findElement的方法。这样就可以在页面上查找元素了。所以我们也在element类中通过这种形式来进行他们之间的关联。我们通过在element类中添加定位方式的形式来进行元素定位和page的关联,我们只需要在编写自己的page类的过程中直接加入element类就可以了,element类提供了所有的关于element的方法,比如鼠标事件和键盘事件,还有更重要的元素定位方法。定位的方法在这里不做任何的推荐,因为每个人的思路不同,实现的方式也不同,我个人比较偏向的做法是做一个xml来进行资源的管理,把所有需要的资源都放入到xml里面,这样我们就可以进行元素的定位了。并且在后期维护中主要维护xml就可以进行对整个脚本进行维护了,不需要我们大量的重新进行源码的分析和修改了。当然这是设计的优化过程,因为定位的实现我们还是需要自己来完成的,我们知道元素的定位方式各种各样,我们怎么来进行管理和定位呢?我们可以通过map的方法作为属性值来进行元素的管理,他的各种定位方法存放在map中,我们需要的时候只需要调一下就可以了。通过观察源码findElement也是通过map的形式来进行元素定位存储的。我们可以借鉴一下源码的实现方式。当然我们完全封装findElement也是可以的。说到这里可能我们有一个问题比较难以解决,那就是层级定位。如果我们只是给element类添加定位方式的话,那么findElement提供的一级一级的定位方式我们就无法应用了,所以在element类中我们必要还要提供findElement的方法进行层级定位。这只是为了把webdriver的所有方法都尽量应用到而已。其实通过xpath的方式我们就可以基本上定位大多数的元素。剩下的内容就是我们对element内容的扩充了。我们可以把元素的更加具体的抽象出来,比如我们把select,table,checkbox等等等的各种html标签元素显式的定义出来,在我们定义一个元素的时候我们能够更加清晰的看到这个元素的含义,我们知道它是一个按钮或者table等等等,这些小元素的操作需要我们自己深入理解和开发,这里不做过多的介绍。

其他类:

通过这些层次的分析我们已经出现一个框架的雏形了,然后我们剩下的设计就是基于完善和优化了。在一个自动化过程中case类是非常重要的,我们需要知道case类运行结束的结果报告和分析,所以case类的运行等等一系列的东西我们都得有统计,这些东西必须要我们提供一些类来实现,不过所幸的是,强大的junit或者testng完全可以取代我们要去做的工作,他们可以很完美的提供这些功能,我们只需要介入这些开源包就可以了。我们使用QTP的过程中我们经常会用到参数化,我们自动化的设计都有了,但是没有参数化的功能怎么办?我们应该先想象一下数据提供的方式。testng提供了一种参数化的形式,但是它是需要在xml里面配置或者硬编码的形式来进行编写。不过它提供了一种dataprovider的方式来进行参数化,它传递参数的形式是Object[][],我们可能希望使用参数的时候通过excel表格来完成,这些都是可以实现的,poi包提供了解析excel的功能,非常的强大。我们可以自己编写解析类来进行参数化的功能编写,具体实现不再过多去说。调用的方式就简单多了,硬性的记住几个注解就可以了。case类的各种运行我们都有了,还需要一些什么扩展呢?很显然就是日志的扩展。日志的设计也是很有技巧的。我们需要用日志监控某一些方法的话,如果前期没有直接加入日志功能,我们可以通过spring的方式来进行日志切入操作。但是我们在观察日志的时候我们通常会希望知道到底运行到哪一步了,我们可以想一想,所有的操作都是基于element或者window的,page的只是一个抽象出来的概念,所以我们只需要把日志加入到每一个element的方法和window的主要方法里面就可以监控到整个运行的过程,毕竟我们不能够去亲自盯着屏幕一直。这样没个方法不外乎就是运行成功和失败,所以我们可以通过这种方式来进行编码。日志的实现我们可以通过通过的log4j或者自己编写一个小的日志系统。都是可行的方案。

扩展类:

也许我们需要这些系统能够有良好的可移植性,我们可以自己编写类加载器,为以后做整个自动化的测试平台做准备。最主要都是我们做的这些操作可能需要越来简单,所以我们可能会因为引入注解的方式来提供编码效率,所以我们还需要为注解类做一些辅助的工作。当然这些注解的开发需要我们做足足够的需求研究,并不是无谓的去开发各种注解。这些注解的应用应该说很广泛,不再多说注解的好处。并且注解还有一点可应用的地方就是放在数据库的操作中,在自动化测试中,其实数据库的测试也是一个大的难点。在这里我们只讨论前端自动化的设计,不过多的讨论别的东西。

前面讲到的这些类的存在形式其实就是在框架里面的一种层次,我们谈论的这些都是基于webdriver的,并且主要基于前端自动化测试的,当然自动化测试不只包括这些,还包括服务器端,接口自动化,单元自动化等等。我个人的能力水平也是很有限,可能很多地方说到的不是很到位,希望能够通过这篇文章能够给那些希望学习自动化,希望编写小测试框架的童鞋,一点点的启发。如果真的有需要想了解的更多,可以留言给我~~互相交流~

深入理解基于selenium的二次开发的更多相关文章

  1. [github项目]基于百度地图二次开发实现的车辆监管(包含车辆定位、车辆图片和方向控制,电子围栏,图形绘制等功能)前端实现(不包含后端实现)

    前言:基于百度地图javascript版本开发,百度地图中所用的key已承诺仅用于测试,不用于商业用途 注:本文所有代码可以到github上进行下载,github地址:http://map.eguid ...

  2. Qt4.8.6+mingw+Qgis2.4.0基于QGis的二次开发

    关于QGis的二次开发,大致看了一下,基本都是在VC+QT的环境下做环境部署,并且QGis的版本号很老.在mingw下直接开发搭建好开发环境的样例少之又少.基于最新的Qgis2.4.0版本号做了对应的 ...

  3. C#基于AE组件二次开发常见问题

    由于本人从事的是在.net平台下进行GIS的二次开发,所以第一篇博文就说一下:我最近在项目中出现的常见的问题,如果能够给大家增加一点点便利,也是我的荣幸,如果大家对于这次博文有什么意见和建议,欢迎大家 ...

  4. 基于Django+celery二次开发动态配置定时任务 ( 一 )

    需求: 前端时间由于开发新上线一大批系统,上完之后没有配套的报表系统.监控,于是乎开发.测试.产品.运营.业务部.财务等等各个部门就跟那饥渴的饿狼一样需要 各种各样的系统数据满足他们.刚开始一天一个还 ...

  5. Linux基于webRTC的二次开发(一)

    最近在做Linux平台下webRTC的二次开发,一路摸索,中间踩了不少坑,这一篇博客先来简单介绍下Linux上如何使用GCC编译webRTC. 为什么使用GCC编译? 这其实是无奈之举,Linux下w ...

  6. 基于Django+celery二次开发动态配置定时任务 ( 二)

    一.需求 结合上一篇,使用djcelery模块开发定时任务时,定时任务的参数都保存在djcelery_periodictask表的args.kwargs字段里,并且是json格式.那么,当定时任务多了 ...

  7. Selenium(二)开发环境的搭建

    1.安装python的开发集成环境 我之前有写,可参考https://www.cnblogs.com/dydxw/p/10405797.html 2.使用selenium打开火狐浏览器 先从selen ...

  8. Linux基于webRTC的二次开发(二) 实现远程桌面共享

    webRTC中的desktop_capture模块提供了捕获桌面和捕获窗口的相关功能,而实现远程桌面共享功能需要将desktop_capture捕获的画面作为peerconnection的视频源,下面 ...

  9. 基于AndroidPn二次开发的可行性

    一.背景 如果要自己搭建,从零开始做或基于开源进行修改扩充,开源的push引擎,90%的博文首推AndroidPN,结合公司现状,最优解决方案就是进行AndroidPN的二次开发了.先看一下这个项目: ...

随机推荐

  1. Linux实战教学笔记02:计算机系统硬件核心知识

    标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...

  2. EntityFramework 7 Left Join Where is error(Test record)

    First of all, my English is very poor, so I may not be a very good expression, very sorry! In this b ...

  3. OpenFlow Switch学习笔记(二)——OpenFlow Ports

    OpenFlow Ports是OpenFlow Switch与剩余网络之间传递Packet的网络接口.OpenFlow Switches之间通过OpenFlow Ports彼此相互逻辑连接.一个Ope ...

  4. 自定义Sharepoint的登陆页面

    转:http://www.cnblogs.com/jecoso/archive/2008/05/25/1207151.html 原文作者:Damon Armstrong 原文地址:http://www ...

  5. 图片组件——axure线框图部件库介绍

    我们在后面的组件使用中,都统一使用"从部件区域拖拽图片组件到页面区域中" 1. 图片载入 1.1 将图片组件拖拽到页面区域 1.2 双击图片组件 1.3 选择合适图片,点击打开 1 ...

  6. redux核心思路和代码解析

    最近在公司内部培训的时候,发现很多小伙伴只是会用redux.react-redux.redux-thunk的api,对于其中的实现原理和数据真正的流向不是特别的清楚,知其然,也要知其所以然,其实red ...

  7. 【mysql】模糊查询的使用

    1.like/not like 关键字的模糊查询(SQL模式) 基础模板:  SELECT  *  FROM   test  WHERE name LIKE '%你好_'     :匹配       ...

  8. Apache RocketMQ在linux上的常用命令

    Apache RocketMQ在linux上的常用命令 进入maven安装后的rocketmq的bin目录  1.启动Name Server  2.启动Broker 3.关闭Name Server 4 ...

  9. 固态硬盘使用简要手册——windows平台

    第一步,请安装它. 第二步,请关闭磁盘整理功能,如图 详细:控制面板--管理工具--任务计划程序 打开界面,设置如下 图1 第三步:预读(Superfetch)和快速搜索(Windows Search ...

  10. Linux下RTL-SDR基础环境安装

    安装 cmake and libusb apt-get install cmake apt-get -dev 安装 RTL-SDR sudo apt-get install rtl-sdr kali已 ...