PageObjects 设计模式
什么是Page Objects(翻譯為:頁面對象?)…
簡單的說,Page Objects是指UI界面上用于與用戶進(jìn)行交互的對象。它可以指整個頁面,也可以指Page上的某個區(qū)域。Page Objects是你的test code的交互對象,是對實(shí)際UI的一種抽象模型化。通過Page Objects可以減少重復(fù)代碼的編寫,例如,很多頁面都有同樣的header,footer,navigator等部分,如果對這些進(jìn)行抽象,只寫一次就可以在其他地方通用了。
注意PageObjects與Page Objects是不一樣的,PageObjects用于特指采用Page Objects進(jìn)行封裝的一種設(shè)計模式(Design Pattern),而不僅僅是多一個空格的區(qū)別。哈。
如何實(shí)現(xiàn)PageObjects設(shè)計模式?
一般情況下,對于一個Page Objects對象,它有兩個方面的特征:
- 自身元素(WebElement)
- 實(shí)現(xiàn)功能 (Services)
自身元素很好理解,就是實(shí)實(shí)在在的頁面元素。而Page Object通常也都是實(shí)現(xiàn)一定的功能的。就Test的開發(fā)人員來說,更關(guān)心的是Page Objects它們實(shí)現(xiàn)了什么交互功能,而不是其內(nèi)部的實(shí)現(xiàn),因此,這里的功能與開發(fā)人員理解的功能是不一樣的。
以用戶登錄為例:在登錄界面,點(diǎn)擊登錄后要么成功,轉(zhuǎn)向首頁。要么失敗,出現(xiàn)提示出錯信息。?
相信這是一個很容易理解的場景吧!
Java?Code可能類似如下:
從上面可以看出,同時封裝了元素以及功能。此處樣例,元素是沒有初始化的。可以通過類似于driver.findElement()的函數(shù)來直接進(jìn)行初始化,另外WebDriver提供了一個PageFactory用于對PageObjects設(shè)計模式進(jìn)行支持,下面將會講到。
通過上面的這段代碼,也展現(xiàn)出了一個重要的問題,那就是assertion不應(yīng)該在Page Objects內(nèi)部,而應(yīng)該由tests進(jìn)行處理。Page Objects只是返回需要驗(yàn)證的信息即可。
總結(jié)
- public方法代表Page提供的功能
- 盡量不要暴露Page的內(nèi)部細(xì)節(jié)
- 不要assertion
- 方法可以返回其他Page Objects
- Page Objects不用代表整個頁面,可以是任意一個部分
- 一樣的操作,不同的結(jié)果應(yīng)該分開(正確登錄,錯誤登錄)
樣例
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
從上面的樣例中,有沒有發(fā)現(xiàn)每個元素都要進(jìn)行driver.findElement()這樣的操作,寫起來好累啊,一堆重復(fù)性的代碼。有沒有更好的,更優(yōu)雅的處理方法呢?org.openqa.selenium.support.PageFactory就是用來負(fù)責(zé)處理這個的,真Happy!?
下面以百度搜索作為樣例場景,搜索一個關(guān)鍵字:
運(yùn)行以上代碼,發(fā)現(xiàn)已經(jīng)可以正常運(yùn)行,結(jié)果如下:
...... 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可見,搜索后,已經(jīng)轉(zhuǎn)向了正確的搜索結(jié)果頁面。然而WebElement是如何初始化的呢?玄機(jī)就在BaiduSearchPage baiduPage = PageFactory.initElements(driver,BaiduSearchPage.class);這行代碼。PageFactory負(fù)責(zé)初始化了Page里的元素,amazing,用起來就是這么的優(yōu)雅。
那么下來,我就要問了:PageFactory是怎么定位元素的呢?
原來PageFactory初始化元素有一個慣例,樣例中將WebElement的名稱定為wd,那么PageFactory將按類似以下的形式對其進(jìn)行初始化:?
driver.findElement(By.id("wd"));
PageFactory認(rèn)為wd是HTML元素的id或者name字段的值,并且優(yōu)先從id開始查找。至此,我們終于知道怎么回事了。
隨著項(xiàng)目的變大,以及使用的更加深入,HTML元素的id,name字段并不一定唯一,并且java?Class的屬性看起來都是一堆無意義的名稱。這些要求我們必須要進(jìn)行改進(jìn)。幸好PageFactory已經(jīng)提前考慮到了這一切,它支持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用于標(biāo)識其只初始化一次,然后緩存起來備用。
感覺還不夠簡潔嗎?繼續(xù)修改:
@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設(shè)計模式并且配合PageFactory使用,將使你的自動化測試優(yōu)雅、易懂、易維護(hù)。
轉(zhuǎn)載于:https://www.cnblogs.com/111testing/p/7198372.html
總結(jié)
以上是生活随笔為你收集整理的PageObjects 设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C Builder中如何利用消息
- 下一篇: asp.net core权限模块的快速构