教你如何写框架------元素管理篇

前言:

我的博客从来都是言简意赅,直接步入正题。

元素对象管理:

元素对象(以下称为locator)的维护与管理很麻烦,因为locator比较多,每个页面上要操作的可能有几十个,如何快速的查找及维护好能够 使我们写脚本的速度及维护速度大大提升。在前端开发中,开发人员通常是把UI样式放在CSS文件中,受此影响,我们也可以把我们的locator放在一个 专门的文件中,按照页面来分类,提取其公共的locator放在公共的文件中,这样或许可以提升些许编写脚本速度及后期维护成本,效果就是如果UI变了, 我们只需要修改对应的页面中的locator就行了,脚本都不需要重新编译(如果是用需要编译的语言,如JAVA),下面我将介绍一下如何放在专门的文件 中,如何解析该文件,及在脚本中如何调用。下面的脚本语言为JAVA。

1、文件类型------yaml

2、java解析yaml文件所需要的jar包:jyaml-1.3.jar,需自已在网上下载。

3、格式介绍:
a. baidu_input后面接上":",直接回车,然后空两格
b. type与value这两个key是固定的,后面接上":",然后空一格,也可以不空,如果value后面是xpath,建议用加上引号,具体去看下yaml的格式,百度一大堆。
c. 在webdriver中,有By.id,By.name,By.xpath,By.className,By.linkText等,我们选取这几种常见的,所以type的冒包后面可用的值为id,name,xpath
d. value的值为type中对应的类型的值,比如百度首页上的输入框的id='kw',所以在yaml文件中的写法如上图所示

4、解析上述的yaml文件:

import org.ho.yaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
 
public class Demo {
 
    private String yamlFile;
 
    public Demo() {    
        yamlFile = "demo";
        this.getYamlFile();
    }
 
    private HashMap<String, HashMap<String, String>> ml;   
 
    @SuppressWarnings("unchecked")
    public void getYamlFile() {
        File f = new File("locator/" + yamlFile + ".yaml");
        try {
            ml = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
                    HashMap.class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }  
}

 

可以在本地创建一个demo.yaml文件,保存在locator目录中,locator与src同级目录,然后写个main方法来调用一个 getYamlFile方法,可以看到解析demo.yaml后的值都赋给了变量ml。解析过程如此简单,解析速度如此之快,yaml文件也比较直观,这 是我选择用yaml文件的原因,当然可能还有其它更好的选择,大家可以自行尝试。

5、我们在写脚本时,元素对象一般是这样写的WebElement element = driver.findElement(By.id("kw"));所以接下来我们要把ml变量里的"value"转换成By对象。添加如下代码

private By getBy(String type, String value) {
    By by = null;
    if (type.equals("id")) {
        by = By.id(value);
    }
    if (type.equals("name")) {
        by = By.name(value);
    }
    if (type.equals("xpath")) {
        by = By.xpath(value);
    }
    if (type.equals("className")) {
        by = By.className(value);
    }
    if (type.equals("linkText")) {
        by = By.linkText(value);
    }
    return by;

 这样通过ml中的type与value的值就对产生一个By对象。

6、By对象产生后,就可以把这个对象传给driver.findElement方法,继而生成一个WebElement对象.

import org.ho.yaml.Yaml;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
 
public class Demo {
 
    private String yamlFile;
    public WebDriver driver;
     
    public Demo() {
        driver = DriverInstance.getInstance();
        yamlFile = "demo";
        this.getYamlFile();
    }
 
    private HashMap<String, HashMap<String, String>> ml;   
 
    @SuppressWarnings("unchecked")
    public void getYamlFile() {
        File f = new File("locator/" + yamlFile + ".yaml");
        try {
            ml = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
                    HashMap.class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    private By getBy(String type, String value) {
        By by = null;
        if (type.equals("id")) {
            by = By.id(value);
        }
        if (type.equals("name")) {
            by = By.name(value);
        }
        if (type.equals("xpath")) {
            by = By.xpath(value);
        }
        if (type.equals("className")) {
            by = By.className(value);
        }
        if (type.equals("linkText")) {
            by = By.linkText(value);
        }
        return by;
    }
     
    public WebElement getElement(String key) {
        String type = ml.get(key).get("type");
        String value = ml.get(key).get("value");
        return driver.findElement(this.getBy(type, value));
    }
     
    public static void main(String[] args){
        Demo d = new Demo();
        WebElement element = d.getElement("baidu_input");
        element.sendKeys("");
    }
}
View Code

7、到这里,已经成功了一半,因为已经把yaml文件中保存的元素成功的转化成了WebElement对象。但是还不够,接下来我们引入一下同步点的 概念,就是在调用locator时,保证locator是显示在页面上的,webdriver中有个WebDriverWait对象,代码如下:

private WebElement watiForElement(final By by) {
    WebElement element = null;
    int waitTime = Integer.parseInt(Config.getConfig("waitTime"));
    try {
        element = new WebDriverWait(driver, waitTime)
                .until(new ExpectedCondition<WebElement>() {
                    public WebElement apply(WebDriver d) {
                        return d.findElement(by);
                    }
                });
    } catch (Exception e) {
        System.out.println(by.toString() + " is not exist until " + waitTime);
    }
    return element;
}

于是乎getElement方法里面就可以改为

public WebElement getElement(String key) {
   String type = ml.get(key).get("type");
   String value = ml.get(key).get("value");
   return this.watiForElement(this.getBy(type, value));
}   

8、到这一步,又改进了一点,新的问题也随之产生了,watiForElement这个方法,返回的WebElement对象包括隐藏的,如果是隐藏的,那么在操作的时候,自然而然会报错,所以,我们得把隐藏的去掉,只显示displayed的元素对象,增加一个方法。

private boolean waitElementToBeDisplayed(final WebElement element) {
    boolean wait = false;
    if (element == null)
        return wait;
    try {
        wait = new WebDriverWait(driver, Integer.parseInt(Config
                .getConfig("waitTime")))
                .until(new ExpectedCondition<Boolean>() {
                    public Boolean apply(WebDriver d) {
                        return element.isDisplayed();
                    }
                });
    } catch (Exception e) {
        System.out.println(element.toString() + " is not displayed");
    }
    return wait;
}

如此一来,getElement方法又可以改进一下了。

public WebElement getElement(String key) {
    String type = ml.get(key).get("type");
    String value = ml.get(key).get("value");
    WebElement element = this.watiForElement(this.getBy(type, value));
    if(!this.waitElementToBeDisplayed(element))
        element = null;
    return element;
}

9、既然有等待元素对象显示的,那么反之就有等待元素对象消失的方法。

public boolean waitElementToBeNonDisplayed(final WebElement element) {
    boolean wait = false;
    if (element == null)
        return wait;
    try {
        wait = new WebDriverWait(driver, Integer.parseInt(Config
                .getConfig("waitTime")))
                .until(new ExpectedCondition<Boolean>() {
                    public Boolean apply(WebDriver d) {
                        return !element.isDisplayed();
                    }
                });
    } catch (Exception e) {
        System.out.println("Locator [" + element.toString()
                + "] is also displayed");
    }
    return wait;
}

10、看上去一切很美好了,but....如果我们要验证一个元素对象不出现在页面上,就会出现问题了,于是增加一个方法

public WebElement getElementNoWait(String key) {
    WebElement element = null;
    String type = ml.get(key).get("type");
    String value = ml.get(key).get("value");
    try{
        element = driver.findElement(this.getBy(type, value));
    }catch(Exception e){
        element = null;
    }
    return element;
}

11、现在的问题是getElement与getElementNoWait的方法体很接近,于是我们来重构下这部分的代码,先增加一个方法,存放相同的方法体

private WebElement getLocator(String key, boolean wait) {
    WebElement element = null;
    if (ml.containsKey(key)) {
        HashMap<String, String> m = ml.get(key);
        String type = m.get("type");
        String value = m.get("value");         
        By by = this.getBy(type, value);
        if (wait) {
            element = this.watiForElement(by);
            boolean flag = this.waitElementToBeDisplayed(element);
            if (!flag)
                element = null;
        } else {
            try {
                element = driver.findElement(by);
            } catch (Exception e) {
                element = null;
            }
        }
    } else
        System.out.println("Locator " + key + " is not exist in " + yamlFile
                + ".yaml");
    return element;
}

再把getElement与getElementNoWait方法进行修改

public WebElement getElement(String key) {     
    return this.getLocator(key, true);
}
 
public WebElement getElementNoWait(String key) {
    return this.getLocator(key, false);
}

12、到现在为止,已经可以满足绝大部分的需求了,完全可以使用了,下面的任务就是来点锦上添花了,举个例子,在yaml文件中,允许使用参数,比如

baidu_input:
  type: id
  value: "%s%s"
baidu_button:
  type: id
  value: "%s"

在这里面的参数用%s来表示,于是在脚本中,我们调用getElement与getElementNoWait方法时需要我们把value给传进去,我们再来处理下这部分,增加一个方法。

private String getLocatorString(String locatorString, String[] ss) {
    for (String s : ss) {
        locatorString = locatorString.replaceFirst("%s", s);
    }
    return locatorString;
}

在上面的方法中,我们可以看到,对于value值,我们是通过一个数组循环的去替代里面的%s,再把该方法结合到getLocator方法中去。

private WebElement getLocator(String key, String[] replace, boolean wait) {
    WebElement element = null;
    if (ml.containsKey(key)) {
        HashMap<String, String> m = ml.get(key);
        String type = m.get("type");
        String value = m.get("value");
        if (replace != null)
            value = this.getLocatorString(value, replace);
        By by = this.getBy(type, value);
        if (wait) {
            element = this.watiForElement(by);
            boolean flag = this.waitElementToBeDisplayed(element);
            if (!flag)
                element = null;
        } else {
            try {
                element = driver.findElement(by);
            } catch (Exception e) {
                element = null;
            }
        }
    } else
        System.out.println("Locator " + key + " is not exist in " + yamlFile
                + ".yaml");
    return element;
}

可以看到getLocator方法的参数变了,于是要重新的更改getElement与getElementNoWait方法,同时重载这两个方法。

public WebElement getElement(String key) {
    return this.getLocator(key, null, true);
}
 
public WebElement getElementNoWait(String key) {
    return this.getLocator(key, null, false);
}
 
public WebElement getElement(String key, String[] replace) {
    return this.getLocator(key, replace, true);
}
 
public WebElement getElementNoWait(String key, String[] replace) {
    return this.getLocator(key, replace, false);
}

13、惊喜?更大的还在后面。再举个例子:

baidu_input:
  type: xpath
  value: "//div[@id='%productId%']//div"
baidu_button:
  type: xpath
  value: "//div[@id='%productId%']//input[@name='button']"

类似于上面这种,整个里面都含有productId, 于是我们可以通过一个方法,调用这个方法后,里面的都会被替换掉,该方法如下。

public void setLocatorVariableValue(String variable, String value){
    Set<String> keys = ml.keySet();
    for(String key:keys){
         String v = ml.get(key).get("value").replaceAll("%"+variable+"%", value);
         ml.get(key).put("value",v);
    }
}

14、再比如,有一些元素对象是每个页面都会出现的,是公共的,这些公共的locator只是有时候要用到,大部分时候都不用,所以,我们把这些公共的放在一个特定的文件里,在需要的时候通过外部加载来使用这些公共的locator,增加一个变量与方法。

private HashMap<String, HashMap<String, String>> extendLocator;
@SuppressWarnings("unchecked")
public void loadExtendLocator(String fileName){
    File f = new File("locator/" + fileName + ".yaml");
    try {
        extendLocator = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
                HashMap.class);
        ml.putAll(extendLocator);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
} 

15、到此为止,整个元素对象管理就结束了,这只是提供一个思路,大家如果有耐心从上到下的给按着来写一遍,应该会了解不少。最后来个总结性的代码。

  1 public class Page {
  2  
  3     public WebDriver driver;
  4  
  5     private String yamlFile;
  6  
  7     public Page() {
  8         driver = DriverInstance.getInstance();     
  9         yamlFile = "demo";
 10         this.getYamlFile();
 11     }
 12  
 13     private HashMap<String, HashMap<String, String>> ml;
 14      
 15     private HashMap<String, HashMap<String, String>> extendLocator;
 16  
 17     @SuppressWarnings("unchecked")
 18     protected void getYamlFile() {
 19         File f = new File("locator/" + yamlFile + ".yaml");
 20         try {
 21             ml = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
 22                     HashMap.class);
 23         } catch (FileNotFoundException e) {
 24             e.printStackTrace();
 25         }
 26     }
 27      
 28     @SuppressWarnings("unchecked")
 29     public void loadExtendLocator(String fileName){
 30         File f = new File("locator/" + fileName + ".yaml");
 31         try {
 32             extendLocator = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
 33                     HashMap.class);
 34             ml.putAll(extendLocator);
 35         } catch (FileNotFoundException e) {
 36             e.printStackTrace();
 37         }
 38     }
 39      
 40     public void setLocatorVariableValue(String variable, String value){
 41         Set<String> keys = ml.keySet();
 42         for(String key:keys){
 43              String v = ml.get(key).get("value").replaceAll("%"+variable+"%", value);
 44              ml.get(key).put("value",v);
 45         }
 46     }
 47  
 48     private String getLocatorString(String locatorString, String[] ss) {
 49         for (String s : ss) {
 50             locatorString = locatorString.replaceFirst("%s", s);
 51         }
 52         return locatorString;
 53     }
 54  
 55     private By getBy(String type, String value) {
 56         By by = null;
 57         if (type.equals("id")) {
 58             by = By.id(value);
 59         }
 60         if (type.equals("name")) {
 61             by = By.name(value);
 62         }
 63         if (type.equals("xpath")) {
 64             by = By.xpath(value);
 65         }
 66         if (type.equals("className")) {
 67             by = By.className(value);
 68         }
 69         if (type.equals("linkText")) {
 70             by = By.linkText(value);
 71         }
 72         return by;
 73     }
 74  
 75     private WebElement watiForElement(final By by) {
 76         WebElement element = null;
 77         int waitTime = Integer.parseInt(Config.getConfig("waitTime"));
 78         try {
 79             element = new WebDriverWait(driver, waitTime)
 80                     .until(new ExpectedCondition<WebElement>() {
 81                         public WebElement apply(WebDriver d) {
 82                             return d.findElement(by);
 83                         }
 84                     });
 85         } catch (Exception e) {
 86             System.out.println(by.toString() + " is not exist until " + waitTime);
 87         }
 88         return element;
 89     }
 90  
 91     private boolean waitElementToBeDisplayed(final WebElement element) {
 92         boolean wait = false;
 93         if (element == null)
 94             return wait;
 95         try {
 96             wait = new WebDriverWait(driver, Integer.parseInt(Config
 97                     .getConfig("waitTime")))
 98                     .until(new ExpectedCondition<Boolean>() {
 99                         public Boolean apply(WebDriver d) {
100                             return element.isDisplayed();
101                         }
102                     });
103         } catch (Exception e) {
104             System.out.println(element.toString() + " is not displayed");
105         }
106         return wait;
107     }
108  
109     public boolean waitElementToBeNonDisplayed(final WebElement element) {
110         boolean wait = false;
111         if (element == null)
112             return wait;
113         try {
114             wait = new WebDriverWait(driver, Integer.parseInt(Config
115                     .getConfig("waitTime")))
116                     .until(new ExpectedCondition<Boolean>() {
117                         public Boolean apply(WebDriver d) {
118                             return !element.isDisplayed();
119                         }
120                     });
121         } catch (Exception e) {
122             System.out.println("Locator [" + element.toString()
123                     + "] is also displayed");
124         }
125         return wait;
126     }
127  
128     private WebElement getLocator(String key, String[] replace, boolean wait) {
129         WebElement element = null;
130         if (ml.containsKey(key)) {
131             HashMap<String, String> m = ml.get(key);
132             String type = m.get("type");
133             String value = m.get("value");
134             if (replace != null)
135                 value = this.getLocatorString(value, replace);
136             By by = this.getBy(type, value);
137             if (wait) {
138                 element = this.watiForElement(by);
139                 boolean flag = this.waitElementToBeDisplayed(element);
140                 if (!flag)
141                     element = null;
142             } else {
143                 try {
144                     element = driver.findElement(by);
145                 } catch (Exception e) {
146                     element = null;
147                 }
148             }
149         } else
150             System.out.println("Locator " + key + " is not exist in " + yamlFile
151                     + ".yaml");
152         return element;
153     }
154  
155     public WebElement getElement(String key) {
156         return this.getLocator(key, null, true);
157     }
158  
159     public WebElement getElementNoWait(String key) {
160         return this.getLocator(key, null, false);
161     }
162  
163     public WebElement getElement(String key, String[] replace) {
164         return this.getLocator(key, replace, true);
165     }
166  
167     public WebElement getElementNoWait(String key, String[] replace) {
168         return this.getLocator(key, replace, false);
169     }
170 }
View Code
posted @ 2015-10-23 15:03  TingJie  阅读(275)  评论(0)    收藏  举报