Selenium 简明教程

Selenium WebDriver - Page Factory

使用 Selenium Webdriver 开发的测试用例可以通过在测试中结合不同的设计模式来简化。其中一种广泛使用 的设计模式是页面对象模型,俗称 POM。为了实现页面对象模型,我们可以借助于被称为页面工厂的工厂类。页面工厂类来自 Selenium Webdriver。

What is a Page Factory?

如前所述,页面工厂是一个帮助实现页面对象模型的类。它是页面对象模型的改进版本,由 Webdriver 类提供。它具有使用注释来初始化构成页面对象的 web 元素的功能。

Features of Page Factory

@FindBy

此注释用于页面工厂中,借助于各种定位器(如 id、名称、类名称、链接文本、部分链接文本、css、xpath 和标签名)来标识、声明和对 web 元素执行操作。

FindBy(name = "elementname")
WebElement e;

@FindBys

这个注释用在 Page Factory 中,用于识别、声明并对 web 元素执行操作,通过使用 ID、名称、类名称、链接文本、部分链接文本、CSS、Xpath 和 Tagname 这些各种定位器,通过指定多重搜索条件来识别。搜索条件中的 ADD 条件必须满足,才能唯一识别一个元素。

@FindBys({
   @FindBy(tagname = "a"),
   @FindBy(linkText = "Search")
})
WebElement lnk;

在上面的示例中,如果满足所有这两个条件,我们将能够识别 Web 元素。

@FindAll

PageFactory 中的此注解类似于 @FindBys,因为它允许使用多个搜索条件。但是,为了唯一找到一个元素,需要满足任何一个条件(条件之间的或条件应为真)。

@FindAll({
   @FindBy(tagname = "a"),
   @FindBy(linkText = "Search"),
   @FindBy(class = "name"),
})
WebElement btn;

在上面的示例中,如果满足三个条件中的任何一个,我们将能够识别一个 Web 元素。

@CacheLookUp

此注解用于 PageFactory 来优化执行速度。这通常用于引用测试中经常使用的元素,例如用户凭据,这对于每个测试用例都是必需的。它允许在首次使用后将经常使用的变量储存在缓存内存中。此注解可以与其他 PageFactory 注解同时使用。

@CacheLookUp
@FindAll({
   @FindBy(tagname = "a"),
   @FindBy(linkText = "Search"),
   @FindBy(class = "name"),
})
WebElement loginBtn;

initElement()

这是 页面工厂 类中用于初始化所有由 @FindBy 注解标识的网页元素的静态方法。

Lazy Initialization

AjaxElementLocatorFactory 基于页面工厂中的延迟加载理念,在执行时定位网页元素并传递超时。通常用于包含 Ajax 元素的应用程序。

Difference between Page Factory and Page Object Model

下面列出了页面工厂和页面对象之间的差异:

  1. 在页面工厂中,元素通过 @FindBy 标识,而在页面对象模型中,元素使用 By 标识。

  2. 页面工厂具有页面对象模型中没有的延迟初始化概念。

  3. 页面对象模型是一种设计模式,而页面工厂是 Webdriver 类中可用于帮助实现页面对象模型的类。

  4. 在页面对象模型中,必须单独初始化每个对象,而在页面工厂中,initElement() 方法一次初始化所有对象。

Example

在下面的示例中,单击 New User

selenium page factory 1

单击 New User 按钮后,我们将转到 Welcome, Register 文本的注册页面。

selenium page factory 2

对于上面的示例,我们将创建两个页面类 - WelcomePage.java 和 RegisterPage.java,我们将在这些各自的页面(使用 @FindBy 注释)上声明网页元素以及对这些元素执行的操作。

我们还将创建测试类 - WelcomePageTest.java,其中将包含实际测试用例、初始化 WelcomePage 和 RegisterPage 的驱动程序对象以及与该测试用例相关的断言。所有测试用例都位于同一 POM 包中。

selenium page factory 3

页面类 WelcomePage.java 上的代码实现。

package POM;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class WelcomePage {
   WebDriver driver;
   @FindBy(xpath = "//*[@id='signInForm']/h1")
   WebElement text;
   @FindBy(xpath = "//*[@id='signInForm']/div[3]/a")
   WebElement btn;;
   public WelcomePage(WebDriver driver) {
      this.driver=driver;

      // initializing all page objects
      PageFactory.initElements(driver, this);
   }
   public String verifyPageHeading() {
      String getHeadtext = text.getText();
      return  getHeadtext;
   }
   public void clickOnNewUser() {
      btn.click();
   }
}

页面类 RegisterPage.java 上的代码实现。

package POM;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class RegisterPage {
   WebDriver driver;
   @FindBy(xpath = "//*[@id='signupForm']/h1")
   WebElement text;
   public RegisterPage(WebDriver driver) {
      this.driver=driver;

      // initializing all page objects
      PageFactory.initElements(driver, this);
   }
   public String verifyPageHeading() {
      String getHeadtext = text.getText();
      return  getHeadtext;
   }
}

测试类 WelcomePageTest.java 上的代码实现。

package POM;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.*;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.assertEquals;

public class WelcomePageTest {
   WebDriver driver;
   WelcomePage objWelcomePage;
   RegisterPage objRegisterPage;

   @BeforeTest
   public void setup() {

      // Initiate the Webdriver
      driver = new ChromeDriver();

      // adding implicit wait of 12 secs
      driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

      // Opening the webpage
      driver.get("https://www.tutorialspoint.com/selenium/practice/login.php");
   }
   @Test(priority = 1)
   public void verifyWelcomePageHeading() {

      // object of WelcomePage page class
      objWelcomePage = new WelcomePage(driver);
      String text = objWelcomePage.verifyPageHeading();
      System.out.println("Page heading in Welcome Page: " + text);

      // assertions to test case
      assertEquals("Welcome, Login In", text);
   }

   @Test(priority = 2)
   public void moveToRegisterPage() {
      objWelcomePage = new WelcomePage(driver);
      objWelcomePage.clickOnNewUser();
   }

   @Test(priority = 3)
   public void verifyRegisterPageHeading() {

      // object of RegisterPage page class
      objRegisterPage = new RegisterPage(driver);
      String text = objRegisterPage.verifyPageHeading();
      System.out.println("Page heading in Register Page: " + text);

      // assertions to test case
      assertEquals("Welcome,Register", text);
   }
   @AfterTest
   public void teardown() {

      // quitting browser
      driver.quit();
   }
}

pom.xml 中的依赖项。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>org.example</groupId>
   <artifactId>SeleniumJava</artifactId>
   <version>1.0-SNAPSHOT</version>
   <properties>
      <maven.compiler.source>16</maven.compiler.source>
      <maven.compiler.target>16</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
   <dependencies>
      <dependency>
         <groupId>org.seleniumhq.selenium</groupId>
         <artifactId>selenium-java</artifactId>
         <version>4.11.0</version>
      </dependency>

      <!-- https://mvnrepository.com/artifact/org.testng/testng -->
      <dependency>
         <groupId>org.testng</groupId>
         <artifactId>testng</artifactId>
         <version>7.9.0</version>
         <scope>test</scope>
      </dependency>
   </dependencies>
</project>
Page heading in Welcome Page: Welcome, Login In
Page heading in Register Page: Welcome,Register

===============================================
Default Suite
Total tests run: 3, Passes: 3, Failures: 0, Skips: 0
===============================================
selenium page factory 4

在上面的示例中,我们首先定位了 Welcome 和 Register 页面上的元素,并在页面类 WelcomePage.java 和 RegisterPage.java 中对这些元素执行了操作。

在测试类 WelcomePageTest.java 中,我们声明了这些页面类的对象以设计测试用例的整个流程。

上面的实现中使用了 TestNG 测试框架和页面工厂。我们在控制台获得了带有消息的页面标题 - Page heading in Welcome Page: Welcome, Login InPage heading in Register Page: Welcome,Register

控制台中的结果有 Total tests run: 3 ,因为有三个方法:

  1. verifyWelcomePageHeading()

  2. moveToRegisterPage()

  3. verifyRegisterPageHeading()

最后,收到消息 Passes: 3Process finished with exit code 0 ,表示代码已成功执行。

Conclusion

以下是对 Selenium WebDriver 页面工厂教程的全面解析。我们从描述页面工厂开始,然后逐步讲解了页面工厂的功能、页面对象模型与页面工厂之间的差异,以及介绍如何结合 Selenium 使用页面工厂的一个示例。这将让你深入了解页面工厂。明智的做法是对学过的内容反复练习,探索其他与 Selenium 相关的知识,以加深理解并拓展视野。