Web UI自动化测试中处理页面元素过期问题

不多说先上代码:

package ec.qa.autotest.ui.common.action;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.SystemClock;
import org.testng.Assert;

import ec.qa.autotest.ui.custom.annotation.PageObject;
import ec.qa.autotest.ui.testbase.TestBase;

@PageObject
public class AdminLoadingProgress {

	@FindAll({ @FindBy(xpath = "//body/div") })
	private List elementsCol;
	private String LOADINGGIF_XPATH = "//body/div[@class='modal-backdrop fade in']";
	private String LOADINGGIF_CLASS = "modal-backdrop fade in";

	public AdminLoadingProgress() {
		PageFactory.initElements(TestBase.getWebDriver(), this);
	}

	public void wiatForLoadingTOComplete() throws InterruptedException {
		Assert.assertEquals(waitForLoadingGIFToDisappear(5000), true);
	}

	public void wiatForLoadingTOComplete(long timeOut) throws InterruptedException {
		Assert.assertEquals(waitForLoadingGIFToDisappear(timeOut), true);
	}

	/**
	 * @author xin.wang
	 * @see 等待loading gif 消失
	 */
	// 获取所有一级DIV元素
	private boolean waitForLoadingGIFToDisappear(long timeOut) throws InterruptedException {
		TestBase.getWebDriver().findElement(By.xpath(LOADINGGIF_XPATH));
		System.out.println("==页面加载中....==");
		SystemClock sc =new SystemClock();
		for (WebElement e : elementsCol) {
			try {
				if (e.getAttribute("class").equals(LOADINGGIF_CLASS)) {
					long endTime = sc.laterBy(timeOut);
					while (sc.isNowBefore(endTime)) {
						if (!elementsCol.contains(e)) {
							System.out.println("==页面加载已完成!==");
							return true;
						}
						TimeUnit.MICROSECONDS.sleep(300);
					}
					return false;
				}
			} catch (StaleElementReferenceException se) {
				System.out.println("==页面元素已过期==");
			}
		}
		System.out.println("==页面加载已完成!==");
		return true;
	}
}

        被测页面在加载数据的时候会向当前DOM中插入一个 DIV[ /body/div[@class='modal-backdrop fade in'] ]块,这个DIV在页面中显示一张GIF图片 用来提示用户 页面正在加载数据,一旦数据加载完成 (document.readyState == 'completed') 页面的JS会将此DIV从当前DOM中移除 (有点诡异 一般做法 就是给此DIV 配一个CSS的display属性就可以了),在自动测试过中 有时就会出现 页面过期的问题,后来自己研究把之前等待LOADINGGIF 消失的方法 改了改  并在过期时候打印出来提示文字,循环跑了 200次 用到这个通用方法的Test Case,没有出现用例报元素过期的异常,但是 从jenkins 的控制台输出 可以看到 还是会出现元素过期的问题 但是我这个方法已经已经抓到这个异常并处理了。

如下jenkins的控制台信息:

Starting ChromeDriver 2.20.353145 (343b531d31eeb933ec778dbcf7081628a1396067) on port 29987Only local connections are allowed.
==页面加载中...
.==页面元素已过期
页面元素已过期=
=页面加载已完成!==

        其实出现过期的并抛异常的语句是这句 :  e.getAttribute("class").equals(LOADINGGIF_CLASS)   
过期原因分析:LOADINGGIF 的DIV 消失了 导致我当前引用到此DIV元素的引用 e 失效 所以webdriver会抛出 StaleElementReferenceException   异常 ,既然GIF消失了 正是我想要的结果 所有直接住到异常并放行程序继续执行。

其实上面的过期问题发生的极少 至少我运行300个左右的CASE 只出现过 1-2次:

Tests run: 203, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------[INFO] 
BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:34 h

但是这属于自动化测试不稳定情况,需要尽可能处理掉,尽可能
保证测试结果的准确性。 

Selenium官网的解释:

Stale Element Reference Exception

You have probably been directed to this page because you've seen a StaleElementReferenceException in your tests.

Common Causes

A stale element reference exception is thrown in one of two cases, the first being more common than the second:

  • The element has been deleted entirely.
  • The element is no longer attached to the DOM.

The Element has been Deleted

The most frequent cause of this is that page that the element was part of has been refreshed, or the user has navigated away to another page. A less common, but still common cause is where a JS library has deleted an element and replaced it with one with the same ID or attributes. In this case, although the replacement elements may look identical they are different; the driver has no way to determine that the replacements are actually what's expected.

If the element has been replaced with an identical one, a useful strategy is to look up the element again. If you do this automatically, be aware that you may well be opening your tests to a race condition and potential flakiness. For example, given the code:

WebElement element = driver.findElement(By.id("example"));String text = element.getText();

If "element.getText" returns before the element is removed from the DOM you'll get one result. If, however, the element is removed from the DOM and your code does an automatic lookup for the element again before "element.getText" a different result may be returned.

Should you wish to head down this route, the simplest hook point is to call setElementConverter.

The Element is not Attached to the DOM

A common technique used for simulating a tabbed UI in a web app is to prepare DIVs for each tab, but only attach one at a time, storing the rest in variables. In this case, it's entirely possible that your code might have a reference to an element that is no longer attached to the DOM (that is, that has an ancestor which is "document.documentElement").

If WebDriver throws a stale element exception in this case, even though the element still exists, the reference is lost. You should discard the current reference you hold and replace it, possibly by locating the element again once it is attached to the DOM.

Edge Cases

  • The element changes type, but keeps the same locator sematics (JQuery and others)

The element changes type, but keeps the same locator sematics (JQuery and others)

Watermarked fields in JQuery change from a regular input to a password field as they get focus. The first end-user key press arrives in the password variant. Refer to pwField2 in   this example  



你可能感兴趣的:(web,UI自动化测试,自动化测试,Webdriver,测试开发,ui,xpath)