Selenium 中的自動化:頁面對像模型和頁面工廠

已發表: 2022-03-11

對於任何敏捷軟件開發團隊來說,編寫自動化測試不僅僅是一種奢侈。 這是一種需要,也是在軟件開發週期的早期階段快速發現錯誤的重要工具。 當有一項新功能仍處於開發階段時,開發人員可以運行自動化測試並查看系統的其他部分如何受到這些更改的影響。 本文將解釋如何使用 Selenium 中的頁面對像模型加速自動化測試。

通過測試自動化,可以降低錯誤修復的成本,並為軟件質量保證 (QA) 流程帶來整體改進。 通過適當的測試,開發人員甚至在進行 QA 之前就有機會發現和解決錯誤。 測試自動化進一步幫助我們自動化不斷退化的測試用例和特性。 這樣,QA 就有更多時間測試應用程序的其他部分。 此外,這有助於確保產品在生產版本中的質量。 因此,我們得到的產品實際上更穩定,質量保證流程更高效。

Selenium 自動化簡化了 Web 應用程序的測試自動化

Selenium 簡化了 Web 應用程序的測試自動化
鳴叫

儘管編寫自動化測試對於開發人員和工程師來說似乎是一件容易的事,但仍有可能導致測試實施不佳,以及任何敏捷過程中代碼維護的高成本。 在涉及測試時,嘗試在任何敏捷開發項目中不斷交付更改或功能可能會被證明是昂貴的。 更改 20 個測試所依賴的網頁上的一個元素將需要一個人通過這 20 個測試例程並更新每個例程以適應這一新引入的更改。 這不僅會非常耗時,而且在早期實施自動化測試時也是一個嚴重的消極因素。

但是,如果我們可以只在一個地方進行更改,並讓每個相關的測試例程都使用它呢? 在本文中,我們將了解 Selenium 中的自動化測試,以及如何使用頁面對像模型來編寫可維護和可重用的測試例程。

Selenium 中的頁面對像模型

頁面對像模型是 Selenium 中的一種對象設計模式,其中網頁被表示為類,頁面上的各種元素被定義為類上的變量。 然後,所有可能的用戶交互都可以作為類上的方法實現:

 clickLoginButton(); setCredentials(user_name,user_password);

由於類中命名良好的方法易於閱讀,因此這是一種實現測試例程的優雅方式,這些例程既可讀又易於維護或在未來更新。 例如:

為了支持 Page Object 模型,我們使用 Page Factory。 Selenium 中的頁面工廠是頁面對象的擴展,可以以多種方式使用。 在這種情況下,我們將使用頁面工廠來初始化在網頁類或頁面對像中定義的 Web 元素。

包含 Web 元素的網頁類或頁面對象需要先使用 Page Factory 進行初始化,然後才能使用 Web 元素變量。 這可以通過使用 PageFactory 上的initElements函數簡單地完成:

 LoginPage page = new LoginPage(driver); PageFactory.initElements(driver, page);

或者,更簡單:

 LoginPage page = PageFactory.intElements(driver,LoginPage.class)

或者,在網頁類構造函數中:

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

Page Factory 將根據配置的“定位器”使用對實際網頁上相應元素的引用來初始化每個WebElement變量。 這是通過使用@FindBy註釋來完成的。 使用此註釋,我們可以定義查找元素的策略以及識別它的必要信息:

 @FindBy(how=How.NAME, using="username") private WebElement user_name;

每次在這個WebElement變量上調用一個方法,驅動都會先在當前頁面找到它,然後模擬交互。 如果我們正在處理一個簡單的頁面,我們知道每次查找都會在頁面上找到該元素,並且我們也知道最終會導航離開該頁面而不返回它,我們可以緩存通過使用另一個簡單的註釋查找字段:

 @FindBy(how=How.NAME, using="username") @CacheLookup private WebElement user_name;

WebElement 變量的整個定義可以用更簡潔的形式替換:

 @FindBy(name="username") private WebElement user_name;

@FindBy註釋支持一些其他策略,使事情變得更容易一些:

 id, name, className, css, tagName, linkText, partialLinkText, xpath
 @FindBy() private WebElement user_name; @FindBy(name="passsword") private WebElement user_password; @FindBy(className="h3") private WebElement label; @FindBy(css=”#content”) private WebElement text;

初始化後,這些 WebElement 變量可用於與頁面上的相應元素進行交互。 例如,以下代碼將:

 user_password.sendKeys(password);

... 將給定的擊鍵序列發送到頁面上的密碼字段,它相當於:

 driver.findElement(By.name(“user_password”)).sendKeys(password);

繼續前進,您經常會遇到需要在頁面上查找元素列表的情況,這就是@FindBys派上用場的時候:

 @FindBys(@FindBy(css=”div[class='yt-lockup-tile yt-lockup-video']”))) private List<WebElement> videoElements;

上面的代碼將找到具有兩個類名“yt-lockup-tile”和“yt-lockup-video”的所有div元素。 我們可以通過將其替換為以下內容來進一步簡化它:

 @FindBy(how=How.CSS,using="div[class='yt-lockup-tile yt-lockup-video']") private List<WebElement> videoElements;

此外,您可以使用帶有多個@FindBy註釋的@FindAll來查找與任何給定定位器匹配的元素:

 @FindAll({@FindBy(how=How.ID, using=”username”), @FindBy(className=”username-field”)}) private WebElement user_name;

現在我們可以將網頁表示為 Java 類並使用 Page Factory 輕鬆初始化WebElement變量,是時候了解如何使用 Page Object 模式和 Page Factory 編寫簡單的 Selenium 測試了。

Java 中的簡單 Selenium 測試自動化項目

對於我們的頁面對像模型教程,讓我們自動化開發人員註冊 Toptal。 為此,我們需要自動化以下步驟:

  • 訪問 www.toptal.com

  • 點擊“申請成為開發者”按鈕

  • 在門戶頁面上首先檢查它是否已打開

  • 點擊“加入Toptal”按鈕

  • 填寫表格

  • 點擊“加入Toptal”按鈕提交表格

設置項目

  • 下載並安裝 Java JDK

  • 下載並安裝 InteliJ Idea

  • 創建一個新的 Maven 項目

  • 將“Project SDK”鏈接到您的 JDK,例如:在 Windows 上“C:\Program Files\Java\jdkxxx”

  • 設置 groupId 和 artifactId:

 <groupId>SeleniumTEST</groupId> <artifactId>Test</artifactId>
  • 在項目 POM 文件中添加依賴項 Selenium 和 JUnit Maven
 <dependencies> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Selenium --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-firefox-driver</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-support</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>${selenium.version}</version> </dependency> </dependencies>

將 Selenium 版本和 JUnit 版本替換為最新版本號,可通過在 Google 和 Selenium 網站上搜索 JUnit Maven 找到。

此時,如果啟用了自動構建,依賴項應該會自動開始下載。 如果沒有,只需在 IntelliJ Idea IDE 右側的 Maven 項目面板下激活 Plugins > install > install:install。

selenium 測試教程 IDE 截圖

項目啟動後,我們可以開始在“src/test/java”下創建我們的測試包。 將包命名為“com.toptal”,並在其下再創建兩個包:“com.toptal.webpages”和“com.toptal.tests”。

selenium 測試教程截圖

我們將把我們的頁面對象/頁面工廠類保存在“com.toptal.webpages”下,將測試例程保存在“com.toptal.tests”下。

現在,我們可以開始創建我們的 Page Object 類了。

主頁頁面對象

我們需要實現的第一個是 Toptal 的主頁 (www.toptal.com)。 在“com.toptal.webpages”下創建一個類並將其命名為“HomePage”。

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class HomePage { private WebDriver driver; //Page URL private static String PAGE_URL="https://www.toptal.com"; //Locators //Apply as Developer Button @FindBy(how = How.LINK_TEXT, using = "APPLY AS A DEVELOPER") private WebElement developerApplyButton; //Constructor public HomePage(WebDriver driver){ this.driver=driver; driver.get(PAGE_URL); //Initialise Elements PageFactory.initElements(driver, this); } public void clickOnDeveloperApplyButton(){ developerApplyButton.click(); } }

確定元素定位器

在 Toptal 的主頁上,我們對一個元素特別感興趣,那就是“申請成為開發者”按鈕。 我們可以通過匹配文本來找到這個元素,這就是我們上面所做的。 在將網頁建模為頁面對像類時,查找和識別元素通常會成為一件苦差事。 使用 Google Chrome 或 Firefox 的調試工具,這可以變得更容易。 通過右鍵單擊頁面上的任何元素,您可以從上下文菜單中激活“檢查元素”選項以查找有關該元素的詳細信息。

一種常見的(也是我首選的)方法是使用 Firefox 的 FireBug 擴展,結合 Selenium 中的 Firefox Web 驅動程序來查找元素。 安裝並啟用 FireBug 擴展後,您可以右鍵單擊頁面並選擇“Inspect element with FireBug”打開 FireBug。 從 FireBug 的 HTML 選項卡,您可以復制頁面上任何元素的 XPath、CSS 路徑、標籤名稱或“Id”(如果可用)。

selenium 中的頁面對像模型:確定元素定位器

通過複製上面屏幕截圖中元素的 XPath,我們可以在我們的 Page Object 中為其創建一個 WebElement 字段,如下所示:

 @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") WebElement heading;

或者為了簡單起見,我們可以在這裡使用標籤名稱“h1”,只要它唯一標識我們感興趣的元素:

 @FindBy(tagName = "h1") WebElement heading;

DeveloperPortalPage 頁面對象

接下來,我們需要一個代表開發人員門戶頁面的頁面對象,我們可以通過單擊“應用為開發人員”按鈕訪問該頁面對象。

在這個頁面上,我們有兩個感興趣的元素。 要確定頁面是否已加載,我們要驗證標題是否存在。 我們還需要一個用於“Join Toptal”按鈕的WebElement字段。

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperPortalPage { private WebDriver driver; @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") private WebElement heading; @FindBy(linkText = "JOIN TOPTAL") private WebElement joinToptalButton; //Constructor public DeveloperPortalPage (WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } //We will use this boolean for assertion. To check if page is opened public boolean isPageOpened(){ return heading.getText().toString().contains("Developer portal"); } public void clikOnJoin(){ joinToptalButton.click(); } }

DeveloperApplyPage 頁面對象

最後,對於這個項目的第三個也是最後一個頁面對象,我們定義了一個代表包含開發人員申請表的頁面。 由於我們必須在此處處理許多表單字段,因此我們為每個表單字段定義一個WebElement變量。 我們通過“id”找到每個字段,並為每個字段定義特殊的 setter 方法,模擬相應字段的擊鍵。

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperApplyPage { private WebDriver driver; @FindBy(tagName = "h1") WebElement heading; @FindBy() WebElement developer_email; @FindBy() WebElement developer_password; @FindBy() WebElement developer_password_confirmation; @FindBy() WebElement developer_full_name; @FindBy() WebElement developer_skype; @FindBy() WebElement join_toptal_button; //Constructor public DeveloperApplyPage(WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } public void setDeveloper_email(String email){ developer_email.clear(); developer_email.sendKeys(email); } public void setDeveloper_password(String password){ developer_password.clear(); developer_password.sendKeys(password); } public void setDeveloper_password_confirmation(String password_confirmation){ developer_password_confirmation.clear(); developer_password_confirmation.sendKeys(password_confirmation); } public void setDeveloper_full_name (String fullname){ developer_full_name.clear(); developer_full_name.sendKeys(fullname); } public void setDeveloper_skype (String skype){ developer_skype.clear(); developer_skype.sendKeys(skype); } public void clickOnJoin(){ join_toptal_button.click(); } public boolean isPageOpened(){ //Assertion return heading.getText().toString().contains("Apply to join our network as a developer"); } }

編寫一個簡單的 Selenium 測試

使用代表我們頁面的 Page Object 類,並將用戶交互作為它們的方法,我們現在可以將簡單的測試例程編寫為一系列簡單的方法調用和斷言。

 package com.toptal.tests; import com.toptal.webpages.DeveloperApplyPage; import com.toptal.webpages.DeveloperPortalPage; import com.toptal.webpages.HomePage; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import java.net.URL; import java.util.concurrent.TimeUnit; public class ApplyAsDeveloperTest { WebDriver driver; @Before public void setup(){ //use FF Driver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Test public void applyAsDeveloper() { //Create object of HomePage Class HomePage home = new HomePage(driver); home.clickOnDeveloperApplyButton(); //Create object of DeveloperPortalPage DeveloperPortalPage devportal= new DeveloperPortalPage(driver); //Check if page is opened Assert.assertTrue(devportal.isPageOpened()); //Click on Join Toptal devportal.clikOnJoin(); //Create object of DeveloperApplyPage DeveloperApplyPage applyPage =new DeveloperApplyPage(driver); //Check if page is opened Assert.assertTrue(applyPage.isPageOpened()); //Fill up data applyPage.setDeveloper_email("[email protected]"); applyPage.setDeveloper_full_name("Dejan Zivanovic Automated Test"); applyPage.setDeveloper_password("password123"); applyPage.setDeveloper_password_confirmation("password123"); applyPage.setDeveloper_skype("automated_test_skype"); //Click on join //applyPage.clickOnJoin(); } @After public void close(){ driver.close(); } }

運行測試

此時,您的項目結構應如下所示:

硒測試示例

如果要運行測試,請從樹中選擇“ApplyAsDeveloperTest”,右鍵單擊它,然後選擇Run 'ApplyAsDeveloperTest'

硒測試示例

運行測試後,您可以在 IDE 的左下角看到結果:

硒測試示例

結論

Page Object 和 Page Factory 可以輕鬆地在 Selenium 中對網頁進行建模並自動測試它們,並使開發人員和 QA 的生活變得更加簡單。 如果操作正確,這些頁面對像類可以在您的整個測試套件中重用,並讓您有機會儘早為您的項目實施自動化 Selenium 測試,而不會影響敏捷開發。 通過在您的頁面對像模型中抽像出用戶交互並保持您的測試例程輕巧簡單,您可以輕鬆地調整您的測試套件以適應不斷變化的需求。

我希望我已經成功地向您展示瞭如何編寫易於維護的漂亮和乾淨的測試代碼。 我將以我最喜歡的 QA 報價結束這篇文章:

三思而後行,編碼一次!

相關:使用無頭瀏覽器進行 Web 抓取:Puppeteer 教程