UI自动化的基本操作就是对页面元素的操作。selenium元素的识别可通过id,name,css,class,xpath等方式来定位,而我在工作中最常用的就是xpath。xpath定位十分灵活,在一段xpath中可以使用多个标签属性来定位,如果目标元素的所有属性都一致,还可以通过父标签,祖标签,和同级标签的不同来区别定位。
一个页面进行自动化操作的第一步就是将该页面的所有元素通过某种定位方式,组织在一个页面类中。再对该页面的业务操作,如增加用户页面的填入用信息操作,定义在一个该页面的操作类中。这就是页面元素与业务操作分离的模式,通常我们说的工厂模式。
在selenium java中通过page包中的PageFactory类来完成元素组织,如下注册页面:
package page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class RegisterPage {
@FindBy(id="mobile")
public WebElement mobile;
@FindBy(id="captcha")
public WebElement verCode;
@FindBy(id="password")
public WebElement psw;
@FindBy(id="confirmPassword")
public WebElement confpsw;
@FindBy(xpath="/html/body/div/div[2]/form/div/div/div[2]/div[6]/div/button")
public WebElement submit_reg;
public RegisterPage(WebDriver driver){
PageFactory.initElements(driver, this);
}
}
每个元素上面通过@FindBy注释来进行元素描述,最下面那个xpath的写法我们不提倡,那是页面直接抓取的绝对路径,稍微有变化就会定位失败,尽量使用相对路径@FindBy(xpath=”//button[@name=’submit’]”)。
selenium ruby没有可直接使用的factory类来使用。如上的xpath改写成:
$driver.find_element(:xpath,'//button[@name=’submit’]')
但是在实际项目中我们不会直接这样写。为了使我们的代码更加灵活并更好的适应UI的变化,按照面向对象的思想,我们会定义一个元素的基类
class ElementBase
# ruby 的构造函数,type通过什么方式来定位,value这个方式相对于的值,name是RSpec中需要取得的元素名字(RSpec是ruby的一个测试框架,类似于testng等,这里不做过多描述,感兴趣的可以自己百度一下)
def initialize(type,value,name="#{self.class}")
@@type=type
@@value=value
@@name=name
end
#该类中定义的第一个方法,调用了selenium的find_element来定位元素
def element
begin
$driver.find_element(@@type.to_sym,@@value)
rescue NoSuchElementError
return false
end
end
end
在该基类中还可以扩展更多的基础方法
class ElementBase
......
def exist?
#调用上面定义的element方法,将返回的对象赋值给类变量@@element
@@element = element
if @@element
#调用selenium的displayed?方法判断该元素是否存在
@@element.displayed?
else
return false
end
end
这样之前那个button的写法就变成了:
module RegisterPage
class BtnSubmit < ElementBase
def initialize
ElementBase.new("xpath","//button[@name='submit']")
end
end
end
module RegisterPage 将该注册页面的元素都放在这个module中,定义一个提交按钮的子类继承于元素基类,在构造函数中定义定位方式和值。在case中要用到该按钮的时候,就实例化该按钮对象即可,如下:
RegisterPage::BtnSubmit.new.exist?