14 Web 自動化測試 -- PageObject 思想

weixin_34321977發表於2018-07-03

到這節課為止我們已經基本上把WebDriver和TestNG的基礎都講完了,下去開始講講實戰過程中我們會用到的一些思想和工具。

例如這節我們要講的PageObject思想。相信如果現在你們的指令碼已經經過幾個迭代的修改了,你們一定會遇到一個頭痛的問題,那就是頁面變化,以前指令碼的定位方式不能用了,得修改定位方式,那如果以往的指令碼沒有用PageObject思想,意味著你得一個一個Case中把需要修改的定位方式找出來,然後再進行修改。這不但照成指令碼維護的成本加大,也可能照成大量程式碼冗餘。

那這時候PageObject就顯得尤為重要。 那什麼是PageObject呢?

什麼是PageObject思想

PageObject 見名思意,就是頁面物件。說白就是把頁面元素定位和頁面元素操作分開。
PageObject在實戰過程中我們回對指令碼實現進行分層。通常做法是分三層:

  1. 物件庫層
  2. 邏輯層
  3. 業務層

物件層用於存放我們的頁面元素和一些特殊控制元件操作。邏輯層則是一些封裝好的功能用例模組。業務層則是我們真正的測試用例的操作。

當然如果我們的測試資料量大時,我們還可以在三層基礎上再加一層 資料層,用於存放我們的測試資料,這也是比較常規的做法。

  1. 物件庫層
  2. 邏輯層
  3. 業務層
  4. 資料層

實戰例子

廢話不多說我們直接來看個例子,我們還是以163郵箱登入為例子。

物件庫層

首先我們新建個叫LoginPage的類,編寫登入頁面所有可能需要操作的元素定位方式和操作,程式碼示例如下:

package com.selenium.pageobjcet;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

/**
 * Created by 米陽 on 14/10/2017.
 */
public class LoginPage {

    // 定位 ifrmae
    public static By loginFrame = By.id("x-URS-iframe");
    // 定位 郵箱地址輸入框
    public static By emailField = By.name("email");
    // 定位 密碼輸入框
    public static By pwdFiled = By.name("password");
    // 定位 登入按鈕
    public static By loginBtn = By.id("dologin");


    WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    /**
     * 往郵箱文字框輸入郵箱
     * @param email 郵箱地址
     */
    public void sendKeysEmail(String email) {
        driver.findElement(emailField).clear();
        driver.findElement(emailField).sendKeys(email);
    }

    /**
     * 往密碼文字框輸入密碼 
     * @param pwd 密碼
     */
    public void sendKeysPWD(String pwd) {
        driver.findElement(pwdFiled).clear();
        driver.findElement(pwdFiled).sendKeys(pwd);
    }

}

這裡我們只把郵件輸入框和密碼輸入框的操作進行封裝,當然如果為了便於閱讀也可以把所有的元素操作進行封裝取名。


操作層

我們再新建個叫LoginMail的類,用於登入邏輯封裝,供業務層Case呼叫,實現如下:

package com.selenium.pageobjcet;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

/**
 * Created by 米陽 on 14/10/2017.
 */
public class LoginMail {
    WebDriver driver;

    public LoginMail(WebDriver driver) {
        this.driver = driver;
    }

    /**
     * 登陸
     *
     * @param emial 郵箱地址
     * @param pwd   密碼
     */
    public void login(String emial, String pwd) {
        LoginPage loginPage = new LoginPage(driver);
        WebElement element = driver.findElement(LoginPage.loginFrame);
        driver.switchTo().frame(element);
        loginPage.sendKeysEmail(emial);
        loginPage.sendKeysPWD(pwd);
        driver.findElement(LoginPage.loginBtn).click();
    }
}

業務層

最後我們來看下業務層的封裝,也就是我們真正Case的編寫:

package com.selenium.pageobjcet;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;

/**
 * Created by 米陽 on 14/10/2017.
 */
public class LoginTest {
    WebDriver driver;

    @BeforeClass
    public void openChrome() {
        System.setProperty("webdriver.chrome.driver", "./drivers/chromedriver.exe");
        driver = new ChromeDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @Test
    public void testLogin2() {
        driver.get("http://mail.163.com/");
        LoginMail loginMail = new LoginMail(driver);
        loginMail.login("meyoungtester", "meyoung123");
    }

    @AfterClass
    public void closedChrome() {
        driver.quit();
    }

}


小結

經過我們對登陸功能的改裝,採用了PageObject思想後,假設以後要是登入頁面的A元素變更,我們就不需要在工程裡面到處找用到這個A元素的Case去修改他們的定位方式,我們只需要開啟我們的LoginPage,找到A元素的定位方式,進行修改,則整個工程用到A元素定位的就自然而然的修改了。同樣如果哪天登入流程變更了,例如登入過程必須輸入驗證碼,那麼我們也不需要把所有Case涉及到登入的都找出來,插入輸入驗證碼過程,只需要在先在LoginPage裡面登陸驗證碼的定位方式,接著加入開啟LoginMail,在登入邏輯裡面加入我們的驗證碼輸入步驟,則用到登入邏輯的所有Case則不需要其他維護。


PageObject 的優點

一張圖差不多對PO思想引入的前後對比。PO思想對介面互動細節進行了封裝,這樣可以使我們的自動化測試指令碼案例更關注業務,而非介面細節,提高了測試案例的可讀性。

1992590-c2b8fc8d89b7a934.png
image.png

PageFactory

PageFactory 整體思想同於PageObject思想,只是表象顯示上不太一樣,它通過註解的方式來定位元素物件,例如:

物件庫層:

    @FindBy(id = "kw")
    public static WebElement emailName;

Case使用:

    @Test
    public void test(){
        driver.get("https://www.baidu.com");
        // 初始化 LoginPage
        PageFactory.initElements(driver ,LoginPage.class);
        LoginPage.emailName.sendKeys("Test");
    }

PageObject VS PageFactor

WebDriver 提供了這兩種元素物件管理的思想,總的來說沒有誰好誰壞,看個人習慣,實際工程也可以兩者結合使用。就個人而言更習慣PageObject思想,但PageFactor也不錯,通過註解方式程式碼看起來更加簡潔。

相關文章