前言:
我的博客从来都是言简意赅,直接步入正题。
元素对象管理:
元素对象(以下称为locator)的维护与管理很麻烦,因为locator比较多,每个页面上要操作的可能有几十个,如何快速的查找及维护好能够使我们写脚本的速度及维护速度大大提升。在前端开发中,开发人员通常是把UI样式放在CSS文件中,受此影响,我们也可以把我们的locator放在一个专门的文件中,按照页面来分类,提取其公共的locator放在公共的文件中,这样或许可以提升些许编写脚本速度及后期维护成本,效果就是如果UI变了,我们只需要修改对应的页面中的locator就行了,脚本都不需要重新编译(如果是用需要编译的语言,如JAVA),下面我将介绍一下如何放在专门的文件中,如何解析该文件,及在脚本中如何调用。下面的脚本语言为JAVA。
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文件的原因,当然可能还有其它更好的选择,大家可以自行尝试。
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对象。
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(""); } }
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)); }
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; }
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; }
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; }
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); }
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); }
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); } }
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(); } }
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); } }