前言:做UI自動化,不可避免的要和頁面上的元素打交道,有的童鞋可能會選擇把頁面元素的定位,操作都寫在測試代碼中,當頁面元素比較少,測試代碼比較少的情況下還好,但是一旦頁面元素多起來(實際運用中也不太可能少),測試代碼一多,就難以閱讀和維護了,因爲元素定位的代碼並不能直接體現我要定位的是哪個元素,當頁面元素變更了,我要去代碼中找到該元素定位的代碼也是比較困難的,這樣就帶了維護問題。
這裏引入我們這個框架主要的設計理念:PO模式,這個我也是學習的大牛前輩,PO模式全稱爲Page Object模式,是webdriver中的一種測試設計模式,主要是將每個頁面設計爲一個class,其中包含了頁面中需要測試的元素(按鈕,輸入框等),這樣在寫腳本時,可以通過調用頁面類來獲取該頁面的元素。並且,當該頁面因爲需求變更,帶來的元素變更時,我們也不需要改測試代碼,只需要改這個頁面類就行了,從而使得測試代碼與頁面元素管理分離。這樣就清晰多了,維護起來也很簡單明瞭。
但是,如果頁面多了,比如我一個後臺系統,有100多個頁面,總不能寫100個類吧,那維護起來也夠嗆,所以我們基於PO模式,再將它改良一下。
如下,進入正題:
先看分層:
1.定義一個頁面基礎類,BasePage,因爲所有的頁面都有共同點,我們可以將他們抽象出來:每個頁面都有元素,每個頁面元素需要做的動作,該類主要要做的就是找到這些元素,並做出相應動作:
package com.etyero.object;
import java.util.HashMap;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.etyero.utils.LogUtil;
import com.etyero.utils.UIExecutorImpl;
import com.etyero.utils.XMLUtil;
/**
* 基礎頁面類
*
* @author ljl
*/
public class BasePage extends UIExecutorImpl {
protected WebDriver driver;
protected String pageName;// 頁面名稱
protected String xmlPath;// 頁面元素配置文件路徑
protected HashMap<String, Locator> locatorMap;//存儲頁面元素信息
public LogUtil log;
public BasePage(WebDriver driver, String pageName) throws Exception {
super(driver);
this.driver = driver;
this.pageName = pageName;
// 獲取page.xml路徑,page.xml在同級目錄
xmlPath = this.getClass().getResource("").getPath() + "page.xml";
locatorMap = XMLUtil.readXMLDocument(xmlPath, pageName);
}
public void click(String locatorName) {
super.click(getLocator(locatorName));
}
public void sendKey(String locatorName, String value) {
super.sendKey(getLocator(locatorName), value);
}
public String getText(String locatorName) {
return super.getText(getLocator(locatorName));
}
public WebElement getElement(String locatorName) {
return super.getElement(getLocator(locatorName));
}
public boolean isElementDisplayed(String locatorName) {
return super.isElementDisplayed(getLocator(locatorName));
}
public void switchWindow(String title) {
super.switchWindow(title);
}
public void switchFrame(String locatorName) {
super.switchFrame(getLocator(locatorName));
}
/**
* 根據locatorName返回對應的locator
*
* @author ljl
*/
public Locator getLocator(String locatorName) {
Locator locator = null;
if (locatorMap != null) {
locator = locatorMap.get(locatorName);
}
return locator;
}
}
2.BasePage類中定義了一個變量,HashMap<String, Locator> locatorMap,這個變量主要存放了頁面元素信息,key爲頁面元素名稱,是我們自己定義的,方便我們知道這個元素是幹嘛的,locator 保存了這個元素的定位方式(如By.id,By.xpath),定位地址(如By.id時的id),等待時長:
package com.etyero.object;
/**
* 封裝頁面元素,每個元素都有相應的定位地址(xpath路徑或css或id),等待時間,定位方式,默認爲By.xpath
*
* @author ljl
*
*/
public class Locator {
private String address; // 定位地址
private int waitSec; // 等待時間
private ByType byType; // 定位方式
/**
* 定位類型枚舉
*
* @author ljl
*
*/
public enum ByType {
by, xpath, linkText, id, name, className
}
public Locator() {
}
/**
* Locator構造器,默認定位類型By.xpath,等待時長3s
*
* @author ljl
* @param element
*/
public Locator(String address) {
this.address = address;
this.waitSec = 3;
this.byType = ByType.xpath;
}
public Locator(String address, int waitSec) {
this.waitSec = waitSec;
this.address = address;
this.byType = ByType.xpath;
}
public Locator(String address, int waitSec, ByType byType) {
this.waitSec = waitSec;
this.address = address;
this.byType = byType;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getWaitSec() {
return waitSec;
}
public void setWaitSec(int waitSec) {
this.waitSec = waitSec;
}
public ByType getByType() {
return byType;
}
public void setByType(ByType byType) {
this.byType = byType;
}
}
3.有了BasePage和Locator類,但是我們的頁面元素怎麼管理呢,這裏我們就要用到xml文件了,我們將要測試的頁面定義爲一個page節點,每個page節點對應一個頁面,這樣就不用寫100個類了;每個page節點下,放該頁面要測試的元素,每個元素我們給他定義好定位方式,定位地址,等待時長,以及元素名稱,元素名稱是爲了方便我們知道這個元素是幹嘛的,能快速找到該元素進行維護。page.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<map>
<page pageName="mainPage">
<!--Locator lists -->
<locator type="xpth" timeOut="30" value="/html/body/div[1]/div[7]">客服熱線</locator>
</page>
<page pageName="minePage">
<!--Locator lists -->
<locator type="id" timeOut="3" value="icon_user">用戶頭像</locator>
<locator type="id" timeOut="3" value="user_name">用戶名</locator>
</page>
<page pageName="loginPage">
<!--Locator lists -->
<locator type="id" timeOut="30" value="txtuser">登錄輸入賬號框</locator>
<locator type="id" timeOut="30" value="txtuserp">登錄輸入密碼框</locator>
<locator type="id" timeOut="30" value="btnLogin">登錄</locator>
<locator type="id" timeOut="30" value="spanMessge">錯誤提示</locator>
</page>
</map>
舉個栗子:如上的loginPage,有賬號,密碼,登錄按鈕,錯誤提示四個要測試的元素,我們給賬號元素定義了一個locator標籤,對應的定位方式爲用id定位,id的值爲txtuser,等待時長30s,該元素名稱我們給它取名爲登錄輸入賬號框,這樣,當登錄框的地址變了,我們可以快速找到,這個是登錄的賬號框,改掉id就行了。另外,解析xml文件用我們第二章中基礎層的XMLUtil類方法。各司其職,清晰明瞭。
以上,對PO模式做了一個簡單的改良,不用再寫那麼多頁面類了,這也是我在大牛那學習的皮毛,相信有更好的方法,希望各位童鞋可以積極交流。