Webdriver的PageObject改造
PageObject中提供了一个@FindBy注解,也非常好用,但由于其是一次性全部初始化所有的WebElement,对于当前还不存在于页面上的Element在初始化时就会报错,为了解决这个问题,自然就不能用这个@FindBy注解了,而我们可以自已去写一个类似的注解来解决这个问题,下面是思路的实现:
//自定义一个@FindBy注解
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface FindBy { String name(); int age(); int lazy() default 0; }
//定义一个TestInfo类来模拟WebElement类
public class TestInfo { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "TestInfo [name=" + name + ", age=" + age + "]"; } }
解析@FindBy注解
public class PageUtil { private static void initialLazyInfo(Object obj, int lazy) { try{ Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { if(field.isAnnotationPresent(FindBy.class) && field.getType().equals(TestInfo.class)){ FindBy findBy = field.getAnnotation(FindBy.class); if(findBy.lazy()==lazy){ TestInfo temp = new TestInfo(); temp.setName(findBy.name()); temp.setAge(findBy.age()); field.setAccessible(true); field.set(obj, temp); } } } }catch(Exception e){ e.printStackTrace(); } } public static void initialLazy(Object obj){ PageUtil.initialLazyInfo(obj, 0); } public static void initialLazy(Object obj, int lazy){ PageUtil.initialLazyInfo(obj, lazy); } }
使用方式
public class DemoPage { public DemoPage() { PageUtil.initialLazy(this); } @FindBy(name="zf1", age=1) private TestInfo info1; @FindBy(name="zf2", age=2, lazy=1) private TestInfo info2; public void test(){ System.out.println("info1 is: " + info1); System.out.println("info2 is: " + info2); PageUtil.initialLazy(this, 1); System.out.println("info2 is: " + info2); } public static void main(String[] args) { DemoPage dp = new DemoPage(); dp.test(); } }
运行结果
info1 is: TestInfo [name=zf1, age=1] info2 is: null info2 is: TestInfo [name=zf2, age=2]
说明
- 将TestInfo初始化进行了分层次的初始化
- 在需要用到的地方用
PageUtil.initialLazy(this, int);
进行初始化
以上虽然实现了分层次的初始化,但是在要用到的地方都需要调用PageUtil.initialLazy(this, int);
,还是显得有点麻烦,要解决这个问题,还得从改造WebElement类开始,然后自定义一个@FindBy注解,并且在需要用到元素的地方再去判断并初始化。
定义@FindBy注解
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface FindBy { String id() default ""; String name() default ""; String className() default ""; String css() default ""; String tagName() default ""; String linkText() default ""; String partialLinkText() default ""; String xpath() default ""; }
Page类实例化时初始化@FindBy注解并赋值给FindElement类将@FindBy注解中的值结赋到一个中间类中去,在Page类进行初始化的时候进行赋值public class FindElement { private String id; private String name; private String className; private String css; private String tagName; private String linkText; private String partialLinkText; private String xpath; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getCss() { return css; } public void setCss(String css) { this.css = css; } public String getTagName() { return tagName; } public void setTagName(String tagName) { this.tagName = tagName; } public String getLinkText() { return linkText; } public void setLinkText(String linkText) { this.linkText = linkText; } public String getPartialLinkText() { return partialLinkText; } public void setPartialLinkText(String partialLinkText) { this.partialLinkText = partialLinkText; } public String getXpath() { return xpath; } public void setXpath(String xpath) { this.xpath = xpath; } }
public class PageUtil { public static void initialWebElement(Object obj) { try{ Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { if(field.isAnnotationPresent(FindBy.class) && field.getType().equals(WebElementExt.class)){ FindBy findBy = field.getAnnotation(FindBy.class); FindElement findElement = new FindElement(); if(!"".equals(findBy.id())){ findElement.setId(findBy.id()); }else if(!"".equals(findBy.name())){ findElement.setName(findBy.name()); }else if(!"".equals(findBy.className())){ findElement.setClassName(findBy.className()); }else if(!"".equals(findBy.css())){ findElement.setCss(findBy.css()); }else if(!"".equals(findBy.tagName())){ findElement.setTagName(findBy.tagName()); }else if(!"".equals(findBy.linkText())){ findElement.setLinkText(findBy.linkText()); }else if(!"".equals(findBy.partialLinkText())){ findElement.setPartialLinkText(findBy.partialLinkText()); }else if(!"".equals(findBy.xpath())){ findElement.setXpath(findBy.xpath()); } WebElementExt ext = new WebElementExt(findElement); field.setAccessible(true); field.set(obj, ext); } } }catch(Exception e){ e.printStackTrace(); } } }
改造WebElement类,利用的是装饰器模式public class WebElementExt implements WebElement { private static WebDriver driver = new FirefoxDriver(); private FindElement findElement; public WebElementExt(FindElement findElement) { this.findElement = findElement; } private WebElement element; private WebElement getWebElement(){ if(element != null){ return element; } if(findElement.getId() != null){ element = this.waitForElement(By.id(findElement.getId())); }else if(findElement.getName() != null){ element = this.waitForElement(By.name(findElement.getName())); }else if(findElement.getClassName() != null){ element = this.waitForElement(By.className(findElement.getClassName())); }else if(findElement.getCss() != null){ element = this.waitForElement(By.cssSelector(findElement.getCss())); }else if(findElement.getTagName() != null){ element = this.waitForElement(By.tagName(findElement.getTagName())); }else if(findElement.getLinkText() != null){ element = this.waitForElement(By.linkText(findElement.getLinkText())); }else if(findElement.getPartialLinkText() != null){ element = this.waitForElement(By.partialLinkText(findElement.getPartialLinkText())); }else if(findElement.getXpath() != null){ element = this.waitForElement(By.xpath(findElement.getXpath())); } if(this.waitElementToBeDisplayed(element)){ return element; } return null; } private WebElement waitForElement(final By by) { WebElement element = null; try { element = new WebDriverWait(driver, 20).until(new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver d) { return d.findElement(by); } }); } catch (Exception e) { e.printStackTrace(); } return element; } private boolean waitElementToBeDisplayed(final WebElement element) { boolean wait = false; if (element == null) return wait; try { wait = new WebDriverWait(driver, 20).until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return element.isDisplayed(); } }); } catch (Exception e) { e.printStackTrace(); } return wait; } @Override public void click() { this.getWebElement(); element.click(); } @Override public void submit() { this.getWebElement(); element.submit(); } @Override public void sendKeys(CharSequence... charSequences) { this.getWebElement(); element.sendKeys(charSequences); } @Override public void clear() { this.getWebElement(); element.clear(); } @Override public String getTagName() { this.getWebElement(); return element.getTagName(); } @Override public String getAttribute(String s) { this.getWebElement(); return element.getAttribute(s); } @Override public boolean isSelected() { this.getWebElement(); return element.isSelected(); } @Override public boolean isEnabled() { this.getWebElement(); return element.isEnabled(); } @Override public String getText() { this.getWebElement(); return element.getText(); } @Override public List<WebElement> findElements(By by) { this.getWebElement(); return element.findElements(by); } @Override public WebElement findElement(By by) { this.getWebElement(); return element.findElement(by); } @Override public boolean isDisplayed() { this.getWebElement(); return element.isDisplayed(); } @Override public Point getLocation() { this.getWebElement(); return element.getLocation(); } @Override public Dimension getSize() { this.getWebElement(); return element.getSize(); } @Override public String getCssValue(String s) { this.getWebElement(); return element.getCssValue(s); } }
经过上面这样改造后,即便是页面中动态加载的元素,也不用担心会报错了,也不用多次初始化了。使用方法
public class DemoPage { public DemoPage() { PageUtil.initialWebElement(this); } @FindBy(xpath="//abc") private WebElementExt element; public void clieckButton(){ element.click(); } }