本系列所有代码 https://github.com/zhangting85/simpleWebtest

本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下selenium页面对象脚本的编写,并提供全部代码。

文中将看到,使用selenium编写的一个高复用性、高可维护性的测试框架的核心部分。

背景就不多介绍了,不用页面对象设计的selenium测试框架多半会存在巨大缺陷,长时间使用后问题多多,并且导致了N多项目失败。或者即使不失败,也让自动化测试人员感觉非常厌烦。比如我见过的一些失败框架:有用一个类封装了一百二十几个selenium操作,用了一个三千多行的上帝类的;有完全不能重用全部用线性代码实现,开发人员小小改动一行代码,自动化测试人员改30多个文件的;还有试图用Spring去实现testNG的测试配置、执行功能的;有不管什么东西都先放个接口再implements的;总之奇奇怪怪的设计千万种(上帝类特别多,上帝类其实真的很累,给上帝减负吧亲。)。

以下是我的精简设计,仅供参考

3个核心类:Page、TestCase、DriverManager; 由于太简单,类图就略了。

Page是所有页面对象的父亲,并在构造方法里调用selenium页面工厂初始化页面。

TestCase是所有测试用例的父亲,一方面,他定义了每个测试用例的前置操作和后置操作,另一方面,他内部有一个嵌套类DriverManager负责处理driver。

DriverManager是TestCase的静态内部类,负责处理driver相关的操作

由于我的测试用例是由TestNG来执行的,通常从一个xml文件开始。指定执行某个包下所有带@Test标签的方法(即测试方法)。这个机制使得我们不用亲自去创建TestCase类的实例。(有的开发人员用Spring来创建TestCase的实例,但我用TestNG更简便。两者实现的功能都是通过配置文件,由框架创建我们需要执行的TestCase类的实例并执行他。)

先贴上代码:

Page

 public class Page {
/**
* 构造方法,被所有Page的子类继承,所以每个页面都可以通过自动调用这个方法来初始化页面对象
* it auto calls by all sub-page
*/
public Page() {
PageFactory.initElements(DriverManager.driver, this);
} }

TestCase和DriverManager

 package simplewebtest.core;

 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
/**
* 所有TestNG TestCase都继承这个类。
* 这个类的功能是让testNG可以设置他的driver类型
* 以及由他的成员driver manager来操作这个case要用到的driver
*/
public class TestCase { /**
* 打log用的对象,this表示具体的子类。
* print log
*/
protected Log log = LogFactory.getLog(this.getClass()); /**
* 决定这个TestCase是用什么浏览器的driver来执行。
* 由于设置了BeforeMethod标签,这个方法将由TestNG在每个TestMethod被执行前调用。
* 他将接收一个从TestNG的xml文件传入的参数表示浏览器种类。
* 告诉manager我要新建的driver的类型。
* runs by testNG, it will be run before every test method to decide the driver type
* @param browser:从testng的xml文件传入的浏览器名称。 默认值为firefox
*/
@BeforeMethod(alwaysRun=true)
@Parameters("brwoser")
protected void testMethodStart(@Optional("firefox") String browser){
DriverManager.setDriver(browser);
} /**
* 在一个测试方法结束时再打一遍名字关闭driver,这部分可以根据需要调整
* runs by testNG, it will be run after every test method to close the driver
*/
@AfterMethod(alwaysRun=true)
protected void testMethodEnd(){
DriverManager.quitDriver();;
} /**
* 打印类名。建议一个CASE只放一个方法。
* Print Class Name
*/
@BeforeClass(alwaysRun=true)
protected void testCaseStart(){
//打印类名
log.info("\\/\\/\\/\\/\\/\\/---TestCase = "+ this.getClass().getSimpleName()+"---\\/\\/\\/\\/\\/\\/");
} /**
* 再次打印类名
* Print Class Name again and separator
*/
@AfterClass(alwaysRun=true)
protected void testCaseEnd(){
//打印类名
log.info("/\\/\\/\\/\\/\\/\\---TestCase = "+ this.getClass().getSimpleName()+"---/\\/\\/\\/\\/\\/\\");
//打印分隔符
log.info("#####################################################");
} /**
* 静态内部类。因为把这些driver相关的东西直接放在TestCase类里,我感觉从逻辑上说不通。引入一个静态内部类来解决。
*/
public static class DriverManager {
/**
* 每个DriverManager只管理一个driver,所以他是static的
* shares the same web driver
*/
public static WebDriver driver;
/**
* 根据TestCase的要求来新建一个driver并保存起来
* crate and saves the driver according to the browser type
*/
public static void setDriver(String browser){
if (browser.equals("firefox")){
driver = new EventFiringWebDriver(new FirefoxDriver()).register(new LogEventListener());
}
//有需求的同学自己在这里添加IE等浏览器的支持
//you can add ie/chrome or other driver here
} /**
* 关浏览器,Windows上需要在这里杀进程的步骤
* quit the driver
*/
public static void quitDriver(){
driver.quit();
} }
}

当测试执行时,原本testNG应该去创建某个具体测试用例(TestCase的某个子类),然后调用里面的@Test方法来执行测试。但是现在这些具体的测试用例有了共有的父类,Java里创建子类实例也就是调用子类构造方法时,会先调用其父类的构造方法,也就是创建他的父类实例。然后TestNG就知道了有这个实例。

接着,因为我们在他的父类也就是TestCase类里定义了使用@BeforeClass @BeforeMethod标签的两个方法,所以在执行子类的@Test前TestNG实际上会先执行这两个方法。于是,我可以在这两个方法里面去打log和启动浏览器。这里,启动浏览器的参数是由TestNG.xml中传入的。我们可以配置好告诉testNG我要用什么浏览器,也可以传入更多配置参数实现更丰富的测试组合。

之后,进入正式的测试用例执行阶段,这里给一个测试用例的例子:

TestJDSearch

package simplewebtest.test.testcases.sample.jd;

import org.testng.annotations.Test;

import simplewebtest.core.TestCase;
import simplewebtest.core.page.sample.jd.JDHomepage;
import simplewebtest.core.page.sample.jd.JDItemlistPage; public class TestJDSearch extends TestCase { /**
* JD首页上搜索一个商品 主要介绍定位某个商品名称的N种写法
*/
@Test
public void searchProduct() throws InterruptedException {
log.info("这是测试方法里的第一句打印的log");
JDHomepage home = new JDHomepage(); //结果页面the expected result page
JDItemlistPage resultPage=home.init().searchHeader.search("巧克力");
//actual result: 用三种方法找出第一个商品名字,作为实际结果.(回字有五种写法:P) String product_1= resultPage.firstproduct.getText();//不推荐,但偶尔有适用场景
String product_2= resultPage.getFirstProductName();//不推荐,但偶尔有适用场景
String product_3= resultPage.getProductNameByIndexMethodOne(1);//推荐写法,但你方法名字不要这么长
String product_4= resultPage.getProductNameByIndexMethodTwo(1);//推荐写法,但你方法名字不要这么长 log.info("第一个商品名字(用第一种取法)= "+product_1);
log.info("第一个商品名字(用第二种取法)= "+product_2);
log.info("第一个商品名字(用第三种取法)= "+product_3);
log.info("第一个商品名字(用第四种取法)= "+product_4); //不加asseriton你的case永远是pass
assert(product_1.contains("巧克力"));
assert(product_1.equals(product_2));
assert(product_1.equals(product_3));
assert(product_1.equals(product_4)); log.info("这是测试方法里的最后一句打印的log");
} }

(这里用到的测试页面JDHomepage我会在下一期详解,但代码在我的github工程上已经有了)

这里,首先新建了一个JDHomepage,他是Page类的子类,并且我没有为他定义构造函数。所以他这里new一个对象时调用的其实是父类Page的构造函数。在这个构造函数里,page类调用了selenium的PageFactory来初始化页面。(所以请开发转的自动化测试人员们不要再通过集成Spring来创建页面了。。)

不管是在具体case里还是在具体page里,我都可以直接使用DriverManager.driver来访问当前driver,因为这个类和对象是静态的并且在test case里BeforeMethod里已经进行初始化。

另外,这个静态的driver会随着test case的创造而创造,随着test case的毁灭而毁灭。也就是说对每一个具体的test case,他会重新被创建和销毁。

如果觉得不理解整个过程,建议下载源代码,单步走一遍。就知道testNG下执行这个测试框架时他的执行流程了。

下一篇继续深入页面对象,讲官网上没有的东西:页面模块。

selenium从入门到应用 - 4,页面对象设计模式的实现的更多相关文章

  1. selenium从入门到应用 - 5,页面对象设计模式下的页面模块

    本系列所有代码 https://github.com/zhangting85/simpleWebtest 本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下 ...

  2. [译]Selenium Python文档:六、页面对象

    本章是介绍页面对象设计模式的教程.一个页面对象代表了web应用用户接口的一片区域,你的测试代码将与之交互的. 使用页面对象模式的好处: 可以创建在多个测试样例中都可使用的可重用代码 减少重复性代码 如 ...

  3. PageObject 页面对象模式

    一.PageObject 页面对象设计模式  (一个页面建一个类,即对象,页面对象) 每个页面都建对应的class,类中包含了页面的输入框.标题.元素等元素,测试代码中测试这个页面时,只需要调用这个页 ...

  4. selenium测试框架篇,页面对象和元素对象的管理

    前期已经做好使用Jenkins做buildhttp://www.cnblogs.com/tobecrazy/p/4529399.html 做自动化框架,不可避免的就是对象库. 有一个好的对象库,可以让 ...

  5. Selenium自动化中DOM,XPATH,CSS定位Web页面对象的优劣性分析

    加速IE浏览器自动化执行效率:Selenium自动化中DOM,XPATH,CSS定位Web页面对象的优劣性分析 1.技术背景       在Web应用中,用户通过键盘在输入框中输入值和鼠标点击按钮,链 ...

  6. selenium webdriver(3)---操作页面对象

    页面对象的相关操作可以通过接口文件org.openqa.selenium.WebElement查看,本文只是对象接口的使用方式,具体的实现方式在org.openqa.selenium.remote.R ...

  7. Selenium高亮页面对象

    使用QTP习惯了,在QTP中可以通过访问对象的highlight方法直接高亮对象,确实很方便,那么如何让Selenium高亮页面的测试对象了,可以通过javascript修改页面对象的属性进而高亮对象 ...

  8. Selenium(Python)页面对象+数据驱动测试框架

    整个工程的目录结构: 常用方法类: class SeleniumMethod(object): # 封装Selenium常用方法 def __init__(self, driver): self.dr ...

  9. Selenium(Python)PageObject页面对象

    使用PageObject页面对象的好处是, 当页面元素的位置发生改变时, 只需要去修改Xpath或者ID, 而不用去修改测试用例本身: 本次的思路是: 1.常用方法类 2.页面对象类 3.测试用例类 ...

随机推荐

  1. 结构型设计模式之代理模式(Proxy)

    结构 意图 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P r o x y 模式常见 ...

  2. 题(NOIP模拟赛Round #10)

    题目描述: 有一张的地图,其中的地方是墙,的地方是路.有两种操作: 给出个地点,询问这个地点中活动空间最大的编号.若询问的位置是墙,则活动空间为:否则活动空间为询问地点通过四联通能到达的点的个数.如果 ...

  3. UVA 10910 Marks Distribution

    题意 把数字T分成N个数的和,保证这N个数中最小的数大于P.求方案数目 另f[i][j]表示把i分成j个数的和的方案数 f[i][j]=f[i][j-1]+f[i-1][j-1]+f[i-2][j-1 ...

  4. linux内核分析之进程地址空间【转】

    转自:http://blog.csdn.net/bullbat/article/details/7106094 版权声明:本文为博主原创文章,未经博主允许不得转载. 本文主要介绍linux内核中进程地 ...

  5. centos 解决:Another app is currently holding the yum lock; waiting for it to exit

    centos执行yum时出现错误: Loaded plugins: fastestmirror, refresh-packagekit, security Existing lock /var/run ...

  6. J.U.C并发框架源码阅读(五)Semaphore

    基于版本jdk1.7.0_80 java.util.concurrent.Semaphore 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is sub ...

  7. Js 利用正则表达式和replace函数获取string中所有被匹配到的文本

    js的replace函数除了替换文本以外还有获取所有被正则表达式匹配到的文本的功能.这里以一个简单的案例来作为演示. 利用正则查找出所有被两个花括号包裹的字符串: var str = '<div ...

  8. Linux下配置APUE的编译环境

    APUE即Unix环境高级编程,本书中几乎所有的程序都包含一个apue.h的头文件,那如何配置这个apue.h呢? 1.我们可以在http://pan.baidu.com/s/1dDxmtbF中下载, ...

  9. Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算

    中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...

  10. hiho一下第133周 2-SAT·hihoCoder音乐节(2-SAT)(强连通)

    2-SAT·hihoCoder音乐节 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 hihoCoder音乐节由hihoCoder赞助商大力主办,邀请了众多嘉宾和知名乐队 ...