PageObjects 设计模式
什么是Page Objects(翻譯為:頁面對象?)…
簡單的說,Page Objects是指UI界面上用于與用戶進行交互的對象。它可以指整個頁面,也可以指Page上的某個區域。Page Objects是你的test code的交互對象,是對實際UI的一種抽象模型化。通過Page Objects可以減少重復代碼的編寫,例如,很多頁面都有同樣的header,footer,navigator等部分,如果對這些進行抽象,只寫一次就可以在其他地方通用了。
注意PageObjects與Page Objects是不一樣的,PageObjects用于特指采用Page Objects進行封裝的一種設計模式(Design Pattern),而不僅僅是多一個空格的區別。哈。
如何實現PageObjects設計模式?
一般情況下,對于一個Page Objects對象,它有兩個方面的特征:
- 自身元素(WebElement)
- 實現功能 (Services)
自身元素很好理解,就是實實在在的頁面元素。而Page Object通常也都是實現一定的功能的。就Test的開發人員來說,更關心的是Page Objects它們實現了什么交互功能,而不是其內部的實現,因此,這里的功能與開發人員理解的功能是不一樣的。
以用戶登錄為例:在登錄界面,點擊登錄后要么成功,轉向首頁。要么失敗,出現提示出錯信息。?
相信這是一個很容易理解的場景吧!
Java?Code可能類似如下:
從上面可以看出,同時封裝了元素以及功能。此處樣例,元素是沒有初始化的。可以通過類似于driver.findElement()的函數來直接進行初始化,另外WebDriver提供了一個PageFactory用于對PageObjects設計模式進行支持,下面將會講到。
通過上面的這段代碼,也展現出了一個重要的問題,那就是assertion不應該在Page Objects內部,而應該由tests進行處理。Page Objects只是返回需要驗證的信息即可。
總結
- public方法代表Page提供的功能
- 盡量不要暴露Page的內部細節
- 不要assertion
- 方法可以返回其他Page Objects
- Page Objects不用代表整個頁面,可以是任意一個部分
- 一樣的操作,不同的結果應該分開(正確登錄,錯誤登錄)
樣例
public class LoginPage {private final WebDriver driver;// 用戶名錄入框private WebElement usernameBox;// 密碼錄入框private WebElement passwordBox;// 提交按鈕private WebElement submitButton;public LoginPage(WebDriver driver) {this.driver = driver;if (!"Login".equals(driver.getTitle())) {throw new IllegalStateException("This is not the login page");}this.usernameBox = driver.findElement(By.id("username"));this.passwordBox = driver.findElement(By.id("passwd"));this.submitButton = driver.findElement(By.id("login"));}public HomePage loginAs(String username, String password) {usernameBox.sendKeys(username);passwordBox.sendKeys(password);submitButton.submit();return new HomePage(driver);} }PageFactory
從上面的樣例中,有沒有發現每個元素都要進行driver.findElement()這樣的操作,寫起來好累啊,一堆重復性的代碼。有沒有更好的,更優雅的處理方法呢?org.openqa.selenium.support.PageFactory就是用來負責處理這個的,真Happy!?
下面以百度搜索作為樣例場景,搜索一個關鍵字:
運行以上代碼,發現已經可以正常運行,結果如下:
...... before search url is:http://www.baidu.com/ ...... after search url is:http://www.baidu.com/s?wd=blueshen&rsv_bp=0&rsv_spt=3可見,搜索后,已經轉向了正確的搜索結果頁面。然而WebElement是如何初始化的呢?玄機就在BaiduSearchPage baiduPage = PageFactory.initElements(driver,BaiduSearchPage.class);這行代碼。PageFactory負責初始化了Page里的元素,amazing,用起來就是這么的優雅。
那么下來,我就要問了:PageFactory是怎么定位元素的呢?
原來PageFactory初始化元素有一個慣例,樣例中將WebElement的名稱定為wd,那么PageFactory將按類似以下的形式對其進行初始化:?
driver.findElement(By.id("wd"));
PageFactory認為wd是HTML元素的id或者name字段的值,并且優先從id開始查找。至此,我們終于知道怎么回事了。
隨著項目的變大,以及使用的更加深入,HTML元素的id,name字段并不一定唯一,并且java?Class的屬性看起來都是一堆無意義的名稱。這些要求我們必須要進行改進。幸好PageFactory已經提前考慮到了這一切,它支持annotations來顯式定位元素。那么上述的百度搜索樣例,可以修改為如下形式:
public class BaiduSearchPage {public static final Logger LOG = LoggerFactory.getLogger(BaiduSearchPage.class);@FindBy(how = How.NAME, using = "wd")@CacheLookupprivate WebElement serachBox;public void searchFor(String keyword) {serachBox.sendKeys(keyword);serachBox.submit();} ...... }明確的指定HOW.NAME,using=”wd”,意為查找name=”wd”的元素,并將其初始化賦值給searchBox這一有意義的屬性名。其中@CacheLookup用于標識其只初始化一次,然后緩存起來備用。
感覺還不夠簡潔嗎?繼續修改:
@FindBy(name = "wd") private WebElement searchBox;這是其簡略模式,還支持各種定位方式。
@FindBy(id="...")@FindBy(className="...")@FindBy(name="...")@FindBy(xpath="...")@FindBy(linkText="...")@FindBy(partialLinkText="...")@FindBy(tagName="...")@FindBy(css="...")同時支持@FindBys用于支持列表元素查找定位,返回List<WebElement>類型。
總之,利用PageObjects設計模式并且配合PageFactory使用,將使你的自動化測試優雅、易懂、易維護。
轉載于:https://www.cnblogs.com/111testing/p/7198372.html
總結
以上是生活随笔為你收集整理的PageObjects 设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C Builder中如何利用消息
- 下一篇: C#实现文件与二进制互转并存入数据库