首页 > 其他 > 详细

Selenium2之搭建框架【元素管理】

时间:2015-10-16 13:21:13      阅读:232      评论:0      收藏:0      [点我收藏+]

元素对象管理:

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

    • 文件类——yaml
      技术分享
    • java解析yaml文件所需要的jar包:jyaml-1.3.jar,需自已在网上下载。
    • 格式介绍:
      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文件中的写法如上图所示
    • 解析上述的yaml文件:
技术分享
 1 import org.ho.yaml.Yaml;
 2 import java.io.File;
 3 import java.io.FileInputStream;
 4 import java.io.FileNotFoundException;
 5 import java.util.HashMap;
 6  
 7 public class Demo {
 8  
 9     private String yamlFile;
10  
11     public Demo() {    
12         yamlFile = "demo";
13         this.getYamlFile();
14     }
15  
16     private HashMap<String, HashMap<String, String>> ml;   
17  
18     @SuppressWarnings("unchecked")
19     public void getYamlFile() {
20         File f = new File("locator/" + yamlFile + ".yaml");
21         try {
22             ml = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
23                     HashMap.class);
24         } catch (FileNotFoundException e) {
25             e.printStackTrace();
26         }
27     }  
28 }
View Code
    • 可以在本地创建一个TestBaidu.yaml文件,保存在locator目录中,locator与src同级目录,然后写个main方法来调用一个getYamlFile方法,可以看到解析TestBaidu.yaml后的值都赋给了变量ml。解析过程如此简单,解析速度如此之快,yaml文件也比较直观,这是我选择用yaml文件的原因,当然可能还有其它更好的选择,大家可以自行尝试。

    • 我们在写脚本时,元素对象一般是这样写的WebElement element = driver.findElement(By.id("kw"));所以接下来我们要把ml变量里的"value"转换成By对象。添加如下代码
技术分享
 1 private By getBy(String type, String value) {
 2     By by = null;
 3     if (type.equals("id")) {
 4         by = By.id(value);
 5     }
 6     if (type.equals("name")) {
 7         by = By.name(value);
 8     }
 9     if (type.equals("xpath")) {
10         by = By.xpath(value);
11     }
12     if (type.equals("className")) {
13         by = By.className(value);
14     }
15     if (type.equals("linkText")) {
16         by = By.linkText(value);
17     }
18     return by;
19 }
View Code
    • 这样通过ml中的type与value的值就对产生一个By对象。

    • By对象产生后,就可以把这个对象传给driver.findElement方法,继而生成一个WebElement对象.
技术分享
 1 import org.ho.yaml.Yaml;
 2 import org.openqa.selenium.By;
 3 import org.openqa.selenium.WebDriver;
 4 import org.openqa.selenium.WebElement;
 5  
 6 import java.io.File;
 7 import java.io.FileInputStream;
 8 import java.io.FileNotFoundException;
 9 import java.util.HashMap;
10  
11 public class Demo {
12  
13     private String yamlFile;
14     public WebDriver driver;
15      
16     public Demo() {
17         driver = DriverInstance.getInstance();
18         yamlFile = "demo";
19         this.getYamlFile();
20     }
21  
22     private HashMap<String, HashMap<String, String>> ml;   
23  
24     @SuppressWarnings("unchecked")
25     public void getYamlFile() {
26         File f = new File("locator/" + yamlFile + ".yaml");
27         try {
28             ml = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
29                     HashMap.class);
30         } catch (FileNotFoundException e) {
31             e.printStackTrace();
32         }
33     }
34      
35     private By getBy(String type, String value) {
36         By by = null;
37         if (type.equals("id")) {
38             by = By.id(value);
39         }
40         if (type.equals("name")) {
41             by = By.name(value);
42         }
43         if (type.equals("xpath")) {
44             by = By.xpath(value);
45         }
46         if (type.equals("className")) {
47             by = By.className(value);
48         }
49         if (type.equals("linkText")) {
50             by = By.linkText(value);
51         }
52         return by;
53     }
54      
55     public WebElement getElement(String key) {
56         String type = ml.get(key).get("type");
57         String value = ml.get(key).get("value");
58         return driver.findElement(this.getBy(type, value));
59     }
60      
61     public static void main(String[] args){
62         Demo d = new Demo();
63         WebElement element = d.getElement("baidu_input");
64         element.sendKeys("");
65     }
66 }
View Code

 

    • 到这里,已经成功了一半,因为已经把yaml文件中保存的元素成功的转化成了WebElement对象。但是还不够,接下来我们引入一下同步点的概念,就是在调用locator时,保证locator是显示在页面上的,webdriver中有个WebDriverWait对象,代码如下:
技术分享
 1 private WebElement watiForElement(final By by) {
 2     WebElement element = null;
 3     int waitTime = Integer.parseInt(Config.getConfig("waitTime"));
 4     try {
 5         element = new WebDriverWait(driver, waitTime)
 6                 .until(new ExpectedCondition<WebElement>() {
 7                     public WebElement apply(WebDriver d) {
 8                         return d.findElement(by);
 9                     }
10                 });
11     } catch (Exception e) {
12         System.out.println(by.toString() + " is not exist until " + waitTime);
13     }
14     return element;
15 }
View Code

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

技术分享
1 public WebElement getElement(String key) {
2        String type = ml.get(key).get("type");
3        String value = ml.get(key).get("value");
4        return this.watiForElement(this.getBy(type, value));
5     }   
View Code
    • 到这一步,又改进了一点,新的问题也随之产生了,watiForElement这个方法,返回的WebElement对象包括隐藏的,如果是隐藏的,那么在操作的时候,自然而然会报错,所以,我们得把隐藏的去掉,只显示displayed的元素对象,增加一个方法。
技术分享
 1 private boolean waitElementToBeDisplayed(final WebElement element) {
 2     boolean wait = false;
 3     if (element == null)
 4         return wait;
 5     try {
 6         wait = new WebDriverWait(driver, Integer.parseInt(Config
 7                 .getConfig("waitTime")))
 8                 .until(new ExpectedCondition<Boolean>() {
 9                     public Boolean apply(WebDriver d) {
10                         return element.isDisplayed();
11                     }
12                 });
13     } catch (Exception e) {
14         System.out.println(element.toString() + " is not displayed");
15     }
16     return wait;
17 }
View Code

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

技术分享
1 public WebElement getElement(String key) {
2     String type = ml.get(key).get("type");
3     String value = ml.get(key).get("value");
4     WebElement element = this.watiForElement(this.getBy(type, value));
5     if(!this.waitElementToBeDisplayed(element))
6         element = null;
7     return element;
8 }
View Code
    • 既然有等待元素对象显示的,那么反之就有等待元素对象消失的方法。
技术分享
 1 public boolean waitElementToBeNonDisplayed(final WebElement element) {
 2     boolean wait = false;
 3     if (element == null)
 4         return wait;
 5     try {
 6         wait = new WebDriverWait(driver, Integer.parseInt(Config
 7                 .getConfig("waitTime")))
 8                 .until(new ExpectedCondition<Boolean>() {
 9                     public Boolean apply(WebDriver d) {
10                         return !element.isDisplayed();
11                     }
12                 });
13     } catch (Exception e) {
14         System.out.println("Locator [" + element.toString()
15                 + "] is also displayed");
16     }
17     return wait;
18 }
View Code
    • 看上去一切很美好了,but....如果我们要验证一个元素对象不出现在页面上,就会出现问题了,于是增加一个方法
技术分享
 1 public WebElement getElementNoWait(String key) {
 2     WebElement element = null;
 3     String type = ml.get(key).get("type");
 4     String value = ml.get(key).get("value");
 5     try{
 6         element = driver.findElement(this.getBy(type, value));
 7     }catch(Exception e){
 8         element = null;
 9     }
10     return element;
11 }
View Code
    • 现在的问题是getElement与getElementNoWait的方法体很接近,于是我们来重构下这部分的代码,先增加一个方法,存放相同的方法体
技术分享
 1 private WebElement getLocator(String key, boolean wait) {
 2     WebElement element = null;
 3     if (ml.containsKey(key)) {
 4         HashMap<String, String> m = ml.get(key);
 5         String type = m.get("type");
 6         String value = m.get("value");         
 7         By by = this.getBy(type, value);
 8         if (wait) {
 9             element = this.watiForElement(by);
10             boolean flag = this.waitElementToBeDisplayed(element);
11             if (!flag)
12                 element = null;
13         } else {
14             try {
15                 element = driver.findElement(by);
16             } catch (Exception e) {
17                 element = null;
18             }
19         }
20     } else
21         System.out.println("Locator " + key + " is not exist in " + yamlFile
22                 + ".yaml");
23     return element;
24 }
View Code

再把getElement与getElementNoWait方法进行修改

技术分享
1 public WebElement getElement(String key) {     
2     return this.getLocator(key, true);
3 }
4  
5 public WebElement getElementNoWait(String key) {
6     return this.getLocator(key, false);
7 }
View Code
    • 到现在为止,已经可以满足绝大部分的需求了,完全可以使用了,下面的任务就是来点锦上添花了,举个例子,在yaml文件中,允许使用参数,比如
技术分享
1 baidu_input:
2   type: id
3   value: "%s%s"
4 baidu_button:
5   type: id
6   value: "%s"
View Code

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

技术分享
1 private String getLocatorString(String locatorString, String[] ss) {
2     for (String s : ss) {
3         locatorString = locatorString.replaceFirst("%s", s);
4     }
5     return locatorString;
6 }
View Code

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

技术分享
 1 private WebElement getLocator(String key, String[] replace, boolean wait) {
 2     WebElement element = null;
 3     if (ml.containsKey(key)) {
 4         HashMap<String, String> m = ml.get(key);
 5         String type = m.get("type");
 6         String value = m.get("value");
 7         if (replace != null)
 8             value = this.getLocatorString(value, replace);
 9         By by = this.getBy(type, value);
10         if (wait) {
11             element = this.watiForElement(by);
12             boolean flag = this.waitElementToBeDisplayed(element);
13             if (!flag)
14                 element = null;
15         } else {
16             try {
17                 element = driver.findElement(by);
18             } catch (Exception e) {
19                 element = null;
20             }
21         }
22     } else
23         System.out.println("Locator " + key + " is not exist in " + yamlFile
24                 + ".yaml");
25     return element;
26 }
View Code

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

技术分享
 1 public WebElement getElement(String key) {
 2     return this.getLocator(key, null, true);
 3 }
 4  
 5 public WebElement getElementNoWait(String key) {
 6     return this.getLocator(key, null, false);
 7 }
 8  
 9 public WebElement getElement(String key, String[] replace) {
10     return this.getLocator(key, replace, true);
11 }
12  
13 public WebElement getElementNoWait(String key, String[] replace) {
14     return this.getLocator(key, replace, false);
15 }
View Code
    • 惊喜?更大的还在后面。再举个例子:
技术分享
1 baidu_input:
2   type: xpath
3   value: "//div[@id=‘%productId%‘]//div"
4 baidu_button:
5   type: xpath
6   value: "//div[@id=‘%productId%‘]//input[@name=‘button‘]"
View Code

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

技术分享
1 public void setLocatorVariableValue(String variable, String value){
2     Set<String> keys = ml.keySet();
3     for(String key:keys){
4          String v = ml.get(key).get("value").replaceAll("%"+variable+"%", value);
5          ml.get(key).put("value",v);
6     }
7 }
View Code
    • 再比如,有一些元素对象是每个页面都会出现的,是公共的,这些公共的locator只是有时候要用到,大部分时候都不用,所以,我们把这些公共的放在一个特定的文件里,在需要的时候通过外部加载来使用这些公共的locator,增加一个变量与方法。
技术分享
 1    private HashMap<String, HashMap<String, String>> extendLocator;
 2 @SuppressWarnings("unchecked")
 3 public void loadExtendLocator(String fileName){
 4     File f = new File("locator/" + fileName + ".yaml");
 5     try {
 6         extendLocator = Yaml.loadType(new FileInputStream(f.getAbsolutePath()),
 7                 HashMap.class);
 8         ml.putAll(extendLocator);
 9     } catch (FileNotFoundException e) {
10         e.printStackTrace();
11     }
12 }
View Code
    • 到此为止,整个元素对象管理就结束了,这只是提供一个思路,大家如果有耐心从上到下的给按着来写一遍,应该会了解不少。最后来个总结性的代码。
技术分享
  1 public class Locator {
  2     
  3     private String yamlfile;
  4     private WebDriver driver;
  5 
  6     private Map<String,Map<String,String>> ml;
  7 
  8     public Locator(WebDriver driver)
  9     {
 10         yamlfile="TestBaidu";
 11         this.getYamlFile();
 12         this.driver=driver;
 13     }
 14     
 15     @SuppressWarnings("unchecked")
 16     public void getYamlFile()
 17     {
 18         File f=new File("locator/"+yamlfile+".yaml");
 19         try{
 20             ml=Yaml.loadType(new FileInputStream(f.getAbsolutePath()),HashMap.class);
 21         }catch(FileNotFoundException e)
 22         {
 23             e.printStackTrace();
 24         }
 25     }
 26 
 27     private By getBy(String type,String value)
 28     {
 29         By by =null;
 30         if(type.equals("id")){
 31             by=By.id(value);
 32         }
 33         if(type.equals("xpath")){
 34             by=By.xpath(value);
 35         }
 36         return by;
 37     }
 38     
 39     private boolean waitElementToBeDisplay(final WebElement element){
 40         boolean wait=false;
 41         if(element ==null)
 42             return wait;
 43         try{
 44             wait=new WebDriverWait(driver,config.waitTime).until(new ExpectedCondition<Boolean>()
 45             {
 46                 public Boolean apply(WebDriver d){
 47                     return element.isDisplayed();
 48                 }
 49             });
 50             }catch(Exception e){
 51             System.out.println(element.toString()+"is not displayed");
 52         }
 53         return wait;
 54     }
 55     
 56     public WebElement getElement(String key)
 57     {
 58         //下面三种写法公用,但重构Loactor后不用
 59 //        String type=ml.get(key).get("type");
 60 //        String value=ml.get(key).get("value");
 61 
 62         //无等待时的写法
 63         //return driver.findElement(this.getBy(type,value));
 64         
 65         //有等待时的写法
 66         //return this.waitForElement(this.getBy(type,value));
 67         
 68         //对元素的可见不可见进行判断的写法
 69 //        WebElement element;
 70 //        element=this.waitForElement(this.getBy(type, value));
 71 //        if(!this.waitElementToBeDisplay(element))
 72 //            element=null;
 73 //        return element;
 74         
 75         //对Locator重构之后
 76         return this.getLocator(key,null,true);
 77     }
 78     
 79     //getElement多态
 80     public WebElement getElement(String key,String[] replace)
 81     {
 82         return this.getLocator(key,replace,true);
 83     }
 84     
 85     private WebElement waitForElement(final By by)
 86     {
 87         WebElement element=null;
 88         int waitTime=config.waitTime;
 89         try{
 90             element=new WebDriverWait(driver,waitTime).until(new ExpectedCondition<WebElement>()
 91             {
 92                 public WebElement apply(WebDriver d){
 93                     return d.findElement(by);
 94                 }
 95             });
 96         }
 97         catch(Exception e){
 98             System.out.println(by.toString()+"is not exist until"+waitTime);
 99         }
100         return element;
101         
102     }
103     
104     //等待对象消失的方法
105     @SuppressWarnings("unused")
106     private boolean waitElementToBeNonDisplay(final WebElement element){
107         boolean wait=false;
108         if(element ==null)
109             return wait;
110         try{
111             wait=new WebDriverWait(driver,config.waitTime).until(new ExpectedCondition<Boolean>()
112                 {    public Boolean apply(WebDriver d){
113                     return !element.isDisplayed();
114                     }
115                 });
116         }
117         catch(Exception e){
118             System.out.println(element.toString()+"is also displayed");
119         }
120         return wait;
121     }
122     
123     public WebElement getElementNoWait(String key)
124     {
125         //对Locator重构之前的做法
126 //        WebElement element;
127 //        String type=ml.get(key).get("type");
128 //        String value=ml.get(key).get("value");
129 //        try{
130 //            element=driver.findElement(this.getBy(type, value));
131 //        }
132 //        catch(Exception e){
133 //            element=null;
134 //        }
135 //        return element;
136         
137         //对Locator重构之后
138         return this.getLocator(key,null,false);
139     }
140     
141     public WebElement getElementNoWait(String key,String[] replace)
142     {
143         return this.getLocator(key,replace,false);
144     }
145     
146     //因为getElment和getElementNoWait方法非常接近,可以将上述两方法合并,对Locator方法重构
147     private WebElement getLocator(String key,String[] replace,boolean wait)
148     {
149         WebElement element=null;
150         if(ml.containsKey(key)){
151             Map<String,String> m=ml.get(key);
152             String type=m.get("type");
153             String value=m.get("value");
154             if(replace!=null)
155                 value=this.getLocatorString(value, replace);
156             By by=this.getBy(type,value);
157             if(wait){
158                 element=this.waitForElement(by);
159                 boolean flag=this.waitElementToBeDisplay(element);
160                 if(!flag)
161                     element=null;
162                 else
163                     try{
164                         element=driver.findElement(by);
165                     }
166                     catch(Exception e)
167                     {
168                         element=null;
169                     }
170             }
171         }
172         else
173         {
174             System.out.println("Locator"+key+"is not exist in"+yamlfile+".yaml");
175             return element;
176         }
177         return element;
178     }
179     
180     private String getLocatorString(String locatorString,String[] ss)
181     {
182         for(String s:ss){
183             locatorString=locatorString.replaceFirst("%s",s);
184         }
185         return locatorString;
186     }
187 
188     
189     /**
190      * @param args
191      */
192     public static void main(String[] args) {
193         // TODO Auto-generated method stub
194         String[] replace={"id","kw"};
195         SeleniumDriver selenium=new SeleniumDriver();
196         WebDriver driver=selenium.getDriver();
197         Locator l=new Locator(driver);
198         driver.navigate().to("http://www.baidu.com");
199         WebElement element=l.getElement("baidu_input");
200         element=l.getElement("baidu_input",replace);
201         element.sendKeys("aa");
202 
203     }
204 
205 }
View Code

 

内容转自:http://www.cnblogs.com/zhangfei/p/3456159.html

Selenium2之搭建框架【元素管理】

原文:http://www.cnblogs.com/leoliyue/p/4884886.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!