selenium+java自动化测试框架之元素管理篇

元素对象管理:

元素对象(以下称为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文件:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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对象。添加如下代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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对象.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    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( "" );
         }
    }

     

  7. 到这里,已经成功了一半,因为已经把yaml文件中保存的元素成功的转化成了WebElement对象。但是还不够,接下来我们引入一下同步点的概念,就是在调用locator时,保证locator是显示在页面上的,webdriver中有个WebDriverWait对象,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        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方法里面就可以改为

    1
    2
    3
    4
    5
        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的元素对象,增加一个方法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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方法又可以改进一下了。

    1
    2
    3
    4
    5
    6
    7
    8
    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. 既然有等待元素对象显示的,那么反之就有等待元素对象消失的方法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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....如果我们要验证一个元素对象不出现在页面上,就会出现问题了,于是增加一个方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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的方法体很接近,于是我们来重构下这部分的代码,先增加一个方法,存放相同的方法体
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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方法进行修改

    1
    2
    3
    4
    5
    6
    7
    public  WebElement getElement(String key) {     
         return  this .getLocator(key, true );
    }
     
    public  WebElement getElementNoWait(String key) {
         return  this .getLocator(key, false );
    }

     

  12. 到现在为止,已经可以满足绝大部分的需求了,完全可以使用了,下面的任务就是来点锦上添花了,举个例子,在yaml文件中,允许使用参数,比如
    1
    2
    3
    4
    5
    6
    baidu_input:
       type: id
       value: "%s%s"
    baidu_button:
       type: id
       value: "%s"

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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方法,同时重载这两个方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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. 惊喜?更大的还在后面。再举个例子:
    1
    2
    3
    4
    5
    6
    baidu_input:
       type: xpath
       value: "//div[@id='%productId%']//div"
    baidu_button:
       type: xpath
       value: "//div[@id='%productId%']//input[@name='button']"

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

    1
    2
    3
    4
    5
    6
    7
    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,增加一个变量与方法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
         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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    public  class  Page {
     
         public  WebDriver driver;
     
         private  String yamlFile;
     
         public  Page() {
             driver = DriverInstance.getInstance();     
             yamlFile = "demo" ;
             this .getYamlFile();
         }
     
         private  HashMap<String, HashMap<String, String>> ml;
         
         private  HashMap<String, HashMap<String, String>> extendLocator;
     
         @SuppressWarnings ( "unchecked" )
         protected  void  getYamlFile() {
             File f = new  File( "locator/"  + yamlFile + ".yaml" );
             try  {
                 ml = Yaml.loadType( new  FileInputStream(f.getAbsolutePath()),
                         HashMap. class );
             } catch  (FileNotFoundException e) {
                 e.printStackTrace();
             }
         }
         
         @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();
             }
         }
         
         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);
             }
         }
     
         private  String getLocatorString(String locatorString, String[] ss) {
             for  (String s : ss) {
                 locatorString = locatorString.replaceFirst( "%s" , s);
             }
             return  locatorString;
         }
     
         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;
         }
     
         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;
         }
     
         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;
         }
     
         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;
         }
     
         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;
         }
     
         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 );
         }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值