Selenium Webdriver 的 PageObject 改造
PageObject中提供了一个@FindBy注解,也非常好用,但由于其是一次性全部初始化所有的WebElement,对于当前还不存在于页面上的Element在初始化时就会报错,为了解决这个问题,自然就不能用这个@FindBy注解了,而我们可以自已去写一个类似的注解来解决这个问题,下面是思路的实现:
自定义一个@FindBy注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface FindBy {
    String name();
    int age();
    int lazy() default 0;
}
定义一个TestInfo类来模拟WebElement类
public class TestInfo {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "TestInfo [name=" + name + ", age=" + age + "]";
    }
}
解析@FindBy注解
public class PageUtil {
    private static void initialLazyInfo(Object obj, int lazy) {
        try{
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                if(field.isAnnotationPresent(FindBy.class) && field.getType().equals(TestInfo.class)){
                    FindBy findBy = field.getAnnotation(FindBy.class);
                    if(findBy.lazy()==lazy){
                        TestInfo temp = new TestInfo();
                        temp.setName(findBy.name());
                        temp.setAge(findBy.age());
                        field.setAccessible(true);
                        field.set(obj, temp);
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void initialLazy(Object obj){
        PageUtil.initialLazyInfo(obj, 0);
    }
    public static void initialLazy(Object obj, int lazy){
        PageUtil.initialLazyInfo(obj, lazy);
    }
}
使用方式
public class DemoPage {
    public DemoPage() {
        PageUtil.initialLazy(this);
    }
    @FindBy(name="zf1", age=1)
    private TestInfo info1;
    @FindBy(name="zf2", age=2, lazy=1)
    private TestInfo info2;
    public void test(){
        System.out.println("info1 is: " + info1);
        System.out.println("info2 is: " + info2);
        PageUtil.initialLazy(this, 1);
        System.out.println("info2 is: " + info2);
    }
    public static void main(String[] args) {
        DemoPage dp = new DemoPage();
        dp.test();
    }
}
运行结果
info1 is: TestInfo [name=zf1, age=1]
info2 is: null
info2 is: TestInfo [name=zf2, age=2]
说明
- 将TestInfo初始化进行了分层次的初始化
 - 在需要用到的地方用
PageUtil.initialLazy(this, int);进行初始化 
以上虽然实现了分层次的初始化,但是在要用到的地方都需要调用PageUtil.initialLazy(this, int);,还是显得有点麻烦,要解决这个问题,还得从改造WebElement类开始,然后自定义一个@FindBy注解,并且在需要用到元素的地方再去判断并初始化。
定义@FindBy注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface FindBy {
    String id() default "";
    String name() default "";
    String className() default "";
    String css() default "";
    String tagName() default "";
    String linkText() default "";
    String partialLinkText() default "";
    String xpath() default "";
}
将@FindBy注解中的值结赋到一个中间类中去,在Page类进行初始化的时候进行赋值
public class FindElement {
    private String id;
    private String name;
    private String className;
    private String css;
    private String tagName;
    private String linkText;
    private String partialLinkText;
    private String xpath;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public String getCss() {
        return css;
    }
    public void setCss(String css) {
        this.css = css;
    }
    public String getTagName() {
        return tagName;
    }
    public void setTagName(String tagName) {
        this.tagName = tagName;
    }
    public String getLinkText() {
        return linkText;
    }
    public void setLinkText(String linkText) {
        this.linkText = linkText;
    }
    public String getPartialLinkText() {
        return partialLinkText;
    }
    public void setPartialLinkText(String partialLinkText) {
        this.partialLinkText = partialLinkText;
    }
    public String getXpath() {
        return xpath;
    }
    public void setXpath(String xpath) {
        this.xpath = xpath;
    }
}
Page类实例化时初始化@FindBy注解并赋值给FindElement类
public class PageUtil {
    public static void initialWebElement(Object obj) {
        try{
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                if(field.isAnnotationPresent(FindBy.class) && field.getType().equals(WebElement.class)){
                    FindBy findBy = field.getAnnotation(FindBy.class);
                    FindElement findElement = new FindElement();
                    if(!"".equals(findBy.id())){
                        findElement.setId(findBy.id());
                    }else if(!"".equals(findBy.name())){
                        findElement.setName(findBy.name());
                    }else if(!"".equals(findBy.className())){
                        findElement.setClassName(findBy.className());
                    }else if(!"".equals(findBy.css())){
                        findElement.setCss(findBy.css());
                    }else if(!"".equals(findBy.tagName())){
                        findElement.setTagName(findBy.tagName());
                    }else if(!"".equals(findBy.linkText())){
                        findElement.setLinkText(findBy.linkText());
                    }else if(!"".equals(findBy.partialLinkText())){
                        findElement.setPartialLinkText(findBy.partialLinkText());
                    }else if(!"".equals(findBy.xpath())){
                        findElement.setXpath(findBy.xpath());
                    }
                    WebElementExt ext = new WebElementExt(findElement);
                    field.setAccessible(true);
                    field.set(obj, ext);
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
改造WebElement类,利用的是装饰器模式
public class WebElementExt implements WebElement {
    private static WebDriver driver = new FirefoxDriver();
    private FindElement findElement;
    public WebElementExt(FindElement findElement) {
        this.findElement = findElement;
    }
    private WebElement element;
    private WebElement getWebElement(){
        if(element != null){
            return element;
        }
        if(findElement.getId() != null){
            element = this.waitForElement(By.id(findElement.getId()));
        }else if(findElement.getName() != null){
            element = this.waitForElement(By.name(findElement.getName()));
        }else if(findElement.getClassName() != null){
            element = this.waitForElement(By.className(findElement.getClassName()));
        }else if(findElement.getCss() != null){
            element = this.waitForElement(By.cssSelector(findElement.getCss()));
        }else if(findElement.getTagName() != null){
            element = this.waitForElement(By.tagName(findElement.getTagName()));
        }else if(findElement.getLinkText() != null){
            element = this.waitForElement(By.linkText(findElement.getLinkText()));
        }else if(findElement.getPartialLinkText() != null){
            element = this.waitForElement(By.partialLinkText(findElement.getPartialLinkText()));
        }else if(findElement.getXpath() != null){
            element = this.waitForElement(By.xpath(findElement.getXpath()));
        }
        if(this.waitElementToBeDisplayed(element)){
            return element;
        }
        return null;
    }
    private WebElement waitForElement(final By by) {
        WebElement element = null;
        try {
            element = new WebDriverWait(driver, 20).until(new ExpectedCondition<WebElement>() {
                public WebElement apply(WebDriver d) {
                    return d.findElement(by);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return element;
    } 
    private boolean waitElementToBeDisplayed(final WebElement element) {
        boolean wait = false;
        if (element == null)
            return wait;
        try {
            wait = new WebDriverWait(driver, 20).until(new ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver d) {
                    return element.isDisplayed();
                }
            });
        } catch (Exception e) {
           e.printStackTrace();
        }
        return wait;
    }
    @Override
    public void click() {
        this.getWebElement();
        element.click();
    }
    @Override
    public void submit() {
        this.getWebElement();
        element.submit();
    }
    @Override
    public void sendKeys(CharSequence... charSequences) {
        this.getWebElement();
        element.sendKeys(charSequences);
    }
    @Override
    public void clear() {
        this.getWebElement();
        element.clear();
    }
    @Override
    public String getTagName() {
        this.getWebElement();
        return element.getTagName();
    }
    @Override
    public String getAttribute(String s) {
        this.getWebElement();
        return element.getAttribute(s);
    }
    @Override
    public boolean isSelected() {
        this.getWebElement();
        return element.isSelected();
    }
    @Override
    public boolean isEnabled() {
        this.getWebElement();
        return element.isEnabled();
    }
    @Override
    public String getText() {
        this.getWebElement();
        return element.getText();
    }
    @Override
    public List<WebElement> findElements(By by) {
        this.getWebElement();
        return element.findElements(by);
    }
    @Override
    public WebElement findElement(By by) {
        this.getWebElement();
        return element.findElement(by);
    }
    @Override
    public boolean isDisplayed() {
        this.getWebElement();
        return element.isDisplayed();
    }
    @Override
    public Point getLocation() {
        this.getWebElement();
        return element.getLocation();
    }
    @Override
    public Dimension getSize() {
        this.getWebElement();
        return element.getSize();
    }
    @Override
    public String getCssValue(String s) {
        this.getWebElement();
        return element.getCssValue(s);
    }
}
使用方法
public class DemoPage {
    public DemoPage() {
        PageUtil.initialWebElement(this);
    }
    @FindBy(xpath="//abc")
    private WebElement element;
    public void clieckButton(){
        element.click();
    }
}
经过上面这样改造后,即便是页面中动态加载的元素,也不用担心会报错了,也不用多次初始化了!
https://testerhome.com/topics/10803
Selenium Webdriver 的 PageObject 改造的更多相关文章
- 【转】Webdriver的PageObject改造By 张飞
		
Webdriver的PageObject改造 PageObject中提供了一个@FindBy注解,也非常好用,但由于其是一次性全部初始化所有的WebElement,对于当前还不存在于页面上的Eleme ...
 - Selenium WebDriver 数据驱动测试框架
		
Selenium WebDriver 数据驱动测试框架,以QQ邮箱添加联系人为示例,测试框架结构如下图,详细内容请阅读吴晓华编著<Selenium WebDiver 实战宝典>: Obje ...
 - 使用httpclient 调用selenium webdriver
		
结合上次研究的selenium webdriver potocol ,自己写http request调用remote driver代替selenium API selenium web driver ...
 - Selenium的PO模式(Page Object Model)|(Selenium Webdriver For Python)
		
研究Selenium + python 自动化测试有近两个月了,不能说非常熟练,起码对selenium自动化的执行有了深入的认识. 从最初无结构的代码,到类的使用,方法封装,从原始函数 ...
 - Selenium WebDriver 之 PageObjects 模式 by Example
		
目录 1. 项目配置 2. 一个WebDriver简单例子 3. 使用Page Objects模式 4. 总结 5. Troubleshooting 6. 参考文档 本篇文章通过例子来阐述一下Sele ...
 - Selenium WebDriver Code
		
Selenium WebDriver 用于模拟浏览器的功能,可以做网站测试用,也可以用来做crawler.我是用eclipse开发的,导入selenium-server-standalone-***. ...
 - selenium webdriver 右键另存为下载文件(结合robot and  autoIt)
		
首先感谢Lakshay Sharma 大神的指导 最近一直在研究selenium webdriver右键菜单,发现selenium webdriver 无法操作浏览器右键菜单,如图 如果我想右键另存为 ...
 - Selenium Webdriver java 积累一
		
Selenium Webdriver 学习: http://jarvi.iteye.com/category/203994 https://github.com/easonhan007/webdriv ...
 - Selenium Webdriver下click失效问题解决
		
最近在使用Selenium Webdriver(Selenium2.0)进行界面自动化测试的时候发现单击事件无效,通过driver.findElement的方式是可以找到click元素的,但是就是cl ...
 
随机推荐
- C#学习笔记(7)——委托
			
说明(2017-5-29 22:22:50): 1. 语法:public delegate void mydel();这一句在类外面,命名空间里面. 2. 专门新建一个方法,参数是委托: public ...
 - egret list不显示问题
			
1.循环滚动 2.单格滚动 不太清楚是把哪个约束勾上了,结果一直不显示,折腾了许久. 另外也不要把下面的这个约束勾上,否则不能滑动.
 - Bootstrap tab插件的使用
			
菜鸟教程链接:http://www.runoob.com/bootstrap/bootstrap-tab-plugin.html 1.例子 <!DOCTYPE html> <html ...
 - 【Unity】自定义编辑器窗口——拓展编辑器功能
			
最近学习了Unity自定义编辑器窗口,下面简单总结,方便用到时回顾. 新建一个脚本: using UnityEngine; using System.Collections; using UnityE ...
 - select 操作选中添加、删除操作Javascript
			
//添加选中项 function addItem() { var myMember = document.getElementById("myMember"); var other ...
 - Android——开源框架Universal-Image-Loader + Fragment使用+轮播广告
			
原文地址: Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二) ...
 - RavenDb学习(三)静态索引
			
在静态索引这块,RavenDb其实的是lucene,所以里面有很多概念,其实都是lucene本身的. .定义静态Indexes documentStore.DatabaseCommands.PutIn ...
 - _mysql.c:29:20: error: Python.h: No such file or directory
			
在Centos系统中安装 pip install MySQL-python 提示: _mysql.c:29:20: error: Python.h: No such file or directory ...
 - 安装Cocos2d-x3.0步骤
			
一.在Windows环境下安装 二.在Mac环境下安装 首先,安装brew工具,参照官方网:http://brew.sh/index_zh-cn.html Cocos2d-x3.0需要安装NDK,SD ...
 - 【转】【WPF】WPF MVVM 简单实例
			
1 新建WPF 应用程序WPFMVVMExample 程序结构如下图所示. 2 Model实现 在Model文件夹下新建业务类StudentModel(类文件StudentModel.cs),类的详细 ...