等待元素 – WebDriver – PageObject模式

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

  1. 点击按钮
  2. 等待元素显示
  3. validation元素(包含例如方法isElementDisplayed())

或者也许有其他好的做法等待元素? 也许我们应该等待在PageObject.class中的方法isElementDisplayed中的元素?

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

所以等待一些元素出现的过于冗长的方法可能是这样的:

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

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

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

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

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

文档实际上非常好。

编辑:回答评论:

好的了解了。 但是如果在点击某个按钮等后出现元素怎么办?

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

 public class PageObject extends LoadableComponent{ 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(); } } 

另外一个有效的概念是测试页面(因为selenium1)来自其中一个selenium测试框架 – 可以在这里使用ISFW 。 它具有延迟加载元素,自定义组件function和自动等待(不是隐式等待以降低性能),内置等待方法具有元素和其他对ajax基础应用程序非常有用的function。

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

  1. 测试页面
  2. 零件
  3. 测试步骤

此外, 报告也是描述性的。