等待元素 - WebDriver - PageObject模式

时间:2013-09-17 07:16:37

标签: java selenium webdriver selenium-webdriver pageobjects

只要我使用PageObject模式,我就想知道在动态页面上应该在哪里等待元素。假设我们有测试方法和pageObject类。我应该做什么(在测试方法中):

  1. 点击按钮
  2. 等待元素显示
  3. 验证元素(包含例如方法isElementDisplayed())
  4. 或许还有其他好的做法可以等待元素?也许我们应该等待PageObject.class中的方法isElementDisplayed中的元素?

2 个答案:

答案 0 :(得分:16)

您应该等待页面对象类中的元素,而不是测试类中的元素,因为您的元素应该在页面对象类中定义,测试类应该不知道任何元素,选择器或类似元素。测试,恕我直言,应该只包含描述测试流程的方法调用链,所有与网站和底层DOM的交互都应该在Page Object类中进行。

因此,等待某个元素出现的过于冗长的方法可能类似于:

private final By yourElement = By.id("id");
@Override
public void isLoaded() throws Error {
    new FluentWait<WebDriver>(driver)
            .withTimeout(60, TimeUnit.SECONDS)
            .pollingEvery(1, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class)
            .ignoring(StaleElementReferenceException.class)
            .until(new Function<WebDriver, Boolean>() {
                @NotNull
                @Override
                public Boolean apply(WebDriver webDriver) {
                    WebElement element = driver.findElement(yourElement);
                    return element != null && element.isDisplayed();
                }
            });
}

简单来说,该函数如果轮询DOM 60秒(每1秒)看一下,如果元素存在于DOM中并且它是可见的(意味着高度和大于1px)。如果元素存在(并显示),则该函数返回找到的元素并停止轮询(尽管isLoaded()方法在此特定情况下不返回该元素)。

如果找不到元素,忽略NoSuchElementException方法可以抛出的findElement是有意义的,StaleElementException表示现在对元素的引用是“陈旧的“ - 该元素不再出现在页面的DOM上。这通常意味着某些东西(最常见的是JS)修改了DOM并且引用不再有效,因此WebDriver需要再次查找它。

当然,更短的代码也可以使用,例如:

    new WebDriverWait(driver, 60)
            .until(ExpectedConditions.visibilityOf(someWebElement));

documentation实际上相当不错。

编辑:回答评论:

  

好的,明白了。但是如果在点击一些元素之后存在元素会怎么样   按钮等?

假设你有一个场景,你有一个按钮,点击该按钮后会出现一个文本框,你想与之互动。

public class PageObject extends LoadableComponent<PageObject>{

    public PageObject() throws Exception {
        driver = getWebDriver();
        PageFactory.initElements(driver, this);
        isLoaded();
    }
    private WebDriver driver = null;

    @FindBy(id = "yourButton")
    private WebElement button;

    @FindBy(id = "textBoxThatAppears")
    private WebElement txtBox;

    @Override
    public void isLoaded() throws Error {
        // Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible.
        waitForVisibility(button);
    }

    private void waitForVisibility(WebElement element) throws Error{
           new WebDriverWait(driver, 60)
                .until(ExpectedConditions.visibilityOf(element));
    }

    public void clickButton(){
        button.click();

    }

    public void interactWithTextbox(String text){
        // Wait for txtBox to be visible, then send text
        waitForVisibility(txtBox);
        txtBox.sendKeys(text);

       // EDIT 27.04.14: 
       // Actually you should not do the assertion here or anywhere in 
       // the pageObject, because when reusing the method in some other test, you might
       // not want to assert, you might wonder that why wouldn't you assert some 
       // specific condition every time, but I would throw that question right back 
       // to you and ask: What is the point of checking the exact same thing over and 
       // over again. There are 2 things, firstly the assertion takes resources (and
       // that can become important when test suite grows, secondly your tests can 
       // simply start failing at the same point when one little condition is not as
       // it should be. Also, having the asserts in the test, makes the test more
       // readable and understandable for others.
         // end edit 27.04.14
        // Next line is no longer recommended by this answer.
         // assert that something happened that you expected.
    }

}

现在你的测试班:

public void TestClass {

     @Test
     public void testClickButtonAndInteractWithTextbox(){
         // Initiate the page object
         Pageobject po = new PageObject();
         po.clickButtonAndWaitForTextbox();
         po.interactWithTextbox("blabla");
         // edit 27.04.14
         assertSomethingGoodHappened();
     }
}

答案 1 :(得分:0)

此处可以使用来自selenium testing-frameworks - ISFW之一的另一个有效的测试页面概念(因为selenium 1)。它具有延迟加载元素,自定义组件功能和自动等待(不是隐式等待以降低性能),内置等待方法具有元素和其他对ajax基础应用程序非常有用的功能。

它为开发测试用例提供了以下构建块:

  1. 测试页
  2. 组件
  3. 测试步骤
  4. 此外,Reporting也是描述性的。