PageObject模式下驅動初始化該放在何處的深入思考


在這裏插入圖片描述

寫在前面

我們在做 UI 自動化或者 API 自動化避免不了會使用 PO 模式,這個思想也確實是個好東西,能幫助我們更好的維護代碼。我們一般會使用公司流傳下來的框架模板,或者自己去 github 上拉取一個項目模板,但是現在我們不妨自己去動手寫一個框架,做一個屬於自己的項目,當我們開始使用 PO 模式的時候,選取了 junit 或者 testng 的時候,我們開始要寫驅動了,但是驅動該放在哪裏呢?一般只有兩個思路,要麼放在 Page 對象中,要麼放在 TestCase 測試用例中,似乎都可以,那放在哪裏最好呢?下面我們會深入項目和場景,配合 TestNg 註解具體分析一下放在哪裏是最優解

一般而言有以下幾種思路

  • 驅動初始化放在 Page
    • 放在 PageCommon 的構造器中,所有 Page 繼承它
    • 放在 MainPage 中,它爲登錄頁面
  • 驅動初始化放在 TestCase
    • 放在 BaseTest 中,所有 TestCase 繼承它

放在 Page

放在 Page 中是個很好的思路,依據 PO 思想,PageObject 中封裝頁面操作的詳細細節,但我們一般不會直接放在每個頁面中,因爲這樣會造成大量冗餘代碼,我們一般把它提出來,做一個 PageCommon 父類,讓所有 Page 繼承它即可

放在 PageCoomon

我們在 PageCommon 中怎麼寫呢?

Ok,我們現在知道了可以放在 PageCommon 中,我們應該放在構造器中

public class PageCommon {
    public WebDriver driver = null;
    // 無參構造器
    public PageCommon() {
        this.driver = new ChromeDriver();
    }
    // 有參構造器
    public PageCommon(WebDriver driver) {
        this.driver = driver;
    }
    
    // 其他操作
}

然後我們在 Page 中怎麼寫呢?

public class BaiDuPage extends PageCommon {
    // 無參構造器
    public BaiDuPage() {
        super();
    }
    // 有參構造器
    public BaiDuPage(WebDriver driver) {
        super(driver);
    }
    
    // 頁面操作細節
}

再然後我們在 TestCase 中怎麼寫呢

public class DemoTest extends BaseTest {
    public BaiDuPage page;
    public BaiDuPage2 page2;
    @BeforeClass
    public void init() {
        page1 = new BaiDuPage();
        page2 = new BaiDuPage2(page1.driver);
    }
    
    // @Test 方法
}

一些疑問

爲什麼 PageCommon 中的驅動不可以是 static 呢,因爲當我們使用多線程跑多個驅動時候,如果其爲 static 會造成跑成一個 driver

那爲什麼 PageCommon 要兩個構造器呢,因爲如果只用一個無參構造器,那麼在有的 測試用例中需要兩個頁面,初始化頁面對象時,會造成創建兩個驅動,但我們的需求是再一個 TestCase 中用一個驅動(瀏覽器)完成測試操作

其他

我個人還是蠻推薦這種寫法,這種寫法有一個不好的地方就是在 TestCase 中非要使用 page1.driver 的形式來傳驅動

放在 MainPage

大致思路就是把驅動啓動放在 MainPage 頁面類的無參構造器中,如果寫了 PageCommon 的話,就會 super 其構造器,把驅動傳上去,其他頁面要用這個驅動就直接 page.driver 即可,和放在 PageCommon 中很像,對不,就是一個放在公用頁面的構造器中,一個放在了首頁構造器中,沒啥太大區別。如果沒有寫 PageCommon,也不要緊,其他一模一樣,其他頁面要用這個驅動直接 page.driver 即可

由於我個人不推薦這種寫法,因爲我認爲這種寫法比較混亂,而且思想其實和前面差不多,所以這裏不詳寫了

放在 TestCase

放在 TestCase 也可以,也是一個很直接的思路,因爲 Page 關注頁面代碼邏輯操作,而 TestCase 關注頁面的業務邏輯操作,而驅動初始化與二者都沒有太大關聯,我們一般也不會單獨放在每個 TestCase 中,原因一樣,因爲這造成大量冗餘代碼,我們一般把它放在 BaseTest 中,讓所有的 TestCase 繼承它,BaseTest 一般我們做測試的配置的初始化操作,PageCommon 我們一般做基礎頁面操作方法的封裝

放在 BaseTest

BaseTest 中怎麼寫呢?

public class BaseTest {
    public WebDriver driver = null;
    // @BeforeSuit
    // @BeforeClass
    
    @BeforeTest
    public void initDriver() {
        driver = new ChromeDriver();
    }
    
    // @AfterTest
    // @AfterClass
    // @AfterSuite
}

TestCase 中怎麼寫呢?

public class DemoTest extends BaseTest {
    public MainPage page1;
    public BaiDuPage page2;
    @BeforeClass
    public void init() {
        page1 = new MainPage(driver);
        page2 = new MainPage(driver);
    }
}

PageCommon 中我們該怎麼寫呢?

public class PageCommon {
    // JS, Actions, WebDriverWait ...
    public WebDriver driver = null;
    
    public PageCommon(WebDriver driver) {
        this.driver = driver;
		// 其他參數初始化
    }
    
    // 其他公用操作
}

一些疑問

爲什麼驅動啓動要放在 BaseTest 的 @BeforeTest 中,因爲方便配合 testng.xml 來做多線程,@BeforeClass 我們可以把登錄操作放在其中

驅動放在 BaseTest 的理由是什麼?因爲我們把 PageCommon 理解成封裝頁面共有操作方法,把 BaseTest 理解成測試執行前的準備操作,因爲我們可以把驅動初始化放在 BaseTest 中而不是 Page 中,Page 只去關注頁面中的具體操作,而不應該關心底層測試的初始化工作,所以依據這種理念把驅動放在 BaseTest 中似乎更合理一點,可是頁面類又需要驅動來控制怎麼辦,只有通過構造器去傳參了

其他

我在實際寫項目,以及在 github 上拉取項目,再加上自己的思考發現,一般而言比較簡單的普通項目,人們一般喜歡把驅動初始化操作放在 Page 中,更加複雜的項目框架我建議放在 BaseTest 中,我目前在 github 上拉取了一些框架,發現都是比較簡單的(因爲稍微好點複雜點的框架都成了各個公司的固有資產了),大部分也都是放在 Page 中,我個人建議放在 BaseTest 中更加友好

寫在後面

不論是放在 Page 中還是 BaseTest 中,我認爲都是可行的,我個人更傾向於 BaseTest 中,根據自己的思考和總結以及項目經驗,我個人搭建了一個功能比較齊全對於大型項目而言比較友好的 Selenium + TestNg 測試框架,希望大家可以捧捧場!

https://github.com/abcnull/webuitest4j

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章