移動UI自動化,看起來美好,踐行起來卻難。做個目光短見的務實主義者。Page Objects Pattern是Selenium官方推崇的方式,最近研究寫測試用例最佳實踐之Page Objects,同時結合Appium的Java Client簡單介紹下如何寫出靠譜的Page Object。
Page Objects
Page Object定義為抽象web app頁面的一系列對象,通過對頁面功能的封裝,它得到了很多好處:
- 減少重復代碼
- 提高測試代碼的可讀性和穩定性
- 測試代碼易於維護
一個簡單的例子
public class BaiduSearchPage {
protected WebDriver driver;
@FindBy(id="kw")
private WebElement kw;
private WebElement su;
public BaiduSearchPage(WebDriver driver) {
super();
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void load(String url) {
driver.get(url);
}
public ResultPage search(String key) {
kw.clear();
kw.sendKeys(key);
su.click();
return new ResultPage(driver);
}
}
推薦的做法
- public 方法暴露Page對象的服務
- WebElement,Driver相關頁面UI細節盡可能隱藏
- 盡量減少Page對象中的Assertion
- 到達新的Page,在方法中返回其它Page,甚至同一頁面也可以返回Page做鏈式操作
- 一個Page對象不需要關注所有細節,只關心需要的對象,需要時再補充
- 不同的結果,同一個操作可以用不同的方法。
Appium 中使用Page Object Pattern
Appium的Java Client是基於WebDriver的,但有了一些改進。比如元素定位不到,Appium Java Client會將Locator詳細信息拋出,而Selenium沒有。
Wait
移動自動化測試Wait是很關鍵的一個動作,既關乎正確性,也關乎效率,我們應該極力避免使用Thread.sleep()或Sleeper.sleepTight()。Appium的客戶端提供了一個類AppiumFieldDecorator可以很方便的設置ImplicitlyWaitTimeOut。FieldDecorator顧名思義,是Page對象Field的Decorator,PageFactory主要就是在Feild上下功夫,將WebElement類型的Feild使用Proxy方法,創建一個增強的WebElement,這個成員在每次操作時,都會先使用注解的定位策略定位,然后再調用WebElement的方法,當然可以通過CacheLookup注解,來緩存定位結果(盡量不這么做)。
PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), pageObject);
如果等待某個頁面元素是否可見,在PageObject中也更簡單
public static void untilElementVisable(final WebElement element,int timeoutInSeconds){
new Wait() {
@Override
public boolean until() {
return element.isDisplayed();
}
}.wait(String.format("Timed out waiting for %s. Waited %s",
element, timeoutInSeconds), timeoutInSeconds);
}
FindBy
在Appium中你會遇到,Selendroid模式和UIAutomator定位差異,比如Selendroid的linkText在UIAutomator中用name,還有就是iOS腳本想和Android共用一份。這在Appium中有了很好的擴充,Appium客戶端會在運行時決定使用哪個Annotation來裝飾WebElement。
@FindBy(name="text")
@SelendroidFindBy(name = "text1")
@iOSFindBy(id="sth")
private WebElement textSelendroid;
ElementInterceptor
總是有這樣或那樣的原因,需要記錄日志,如果方法的執行每一步都要手寫是很痛苦的,自然我們想到了AOP。在Selenium中EventFiringWebDriver類可以方便的記錄日志,但是在Appium客戶端中,我們可以修改AppiumFieldDecorator中ElementInterceptor來加入自己的日志信息,不過暫時這個功能Appium Client沒有暴露出來,需要自己fork個repo修改下。
參考
http://assertselenium.com/automation-design-practices/page-object-pattern/
https://code.google.com/p/selenium/wiki/LoadableComponent
https://code.google.com/p/selenium/wiki/PageObjects
https://code.google.com/p/selenium/wiki/PageFactory
https://github.com/FluentLenium/FluentLenium
https://github.com/countableSet/webdriver-demo