Selenium 简明教程

Selenium - Hybrid Driven Framework

Selenium Webdriver 可用于开发基于混合驱动框架的测试脚本。混合驱动框架是关键字驱动框架和数据驱动框架的结合。因此,在混合框架中,我们结合了关键字驱动和数据驱动框架的优势。

Why Hybrid Framework is Used?

混合框架被采用来利用关键字和数据驱动框架的必要特性。它有助于使测试用例更灵活,并且各个特性可以独立存在,而不会影响其他特性。使用混合框架创建的测试用例更易于维护,并且向这种类型框架中添加新测试用例需要的时间更少。

Advantages of Hybrid Framework

混合框架的优点如下 −

  1. 它是免费的开源的。

  2. 可以跨多个平台、浏览器和设备使用。

  3. 易于维护且可扩展。

Disadvantages of Hybrid Framework

混合框架的缺点如下 −

  1. 创建混合框架需要技术专长。

  2. 很难将使用混合框架创建的测试用例移植到另一个应用程序。

  3. 测试脚本的可读性可能成为一个挑战。

Basic Components of Hybrid Framework

混合框架的基本组件在以下图表中描述:

selenium hybrid driven framework 1

如上图所示,混合框架分为两个阶段:实施和开发阶段,以及报告生成阶段。报告生成阶段可以进一步扩展,加入持续集成阶段。对于持续集成阶段,我们可以借助 Jenkins 和其他与 Git(用于代码版本控制)一起使用的工具。

Example

让我们以以下页面的示例为例,其中我们会将 First Name 输入为 Ram ,将 Last Name 输入为 Ganesh ,然后使用混合框架验证在注册页面中输入的值。

selenium hybrid driven framework 2

根据先前所示的图表,我们会创建一个项目 Hybrid ,内容包括创建混合框架而开发的文件夹和包。

selenium hybrid driven framework 3

Prerequisites

  1. 在系统中安装 Java(高于 8 的版本)并使用命令检查其是否存在:java -version。如果安装已成功完成,将显示已安装的 Java 版本。

  2. 在系统中安装 maven 并使用以下命令检查它是否存在:mvn -version。如果已成功完成安装,将显示已安装的 maven 版本。

  3. 安装任何一个 IDE,例如 Eclipse、IntelliJ 等等。

  4. 从链接中添加 TestNG 依赖项 TestNG

  5. 从链接 Selenium Java 中添加 Selenium Java 依赖项。

  6. 从链接 Maven Artifacts 中添加 Log4j 依赖项。

  7. 从链接 Apache POI Common 中添加 Apache POI Common 依赖项。

  8. 从链接 Apache POI API Based 中添加 Apache POI API Based On OPC and OOXML Schemas 依赖项。

  9. 使用所有依赖项保存 pom.xml 并更新 Maven 项目

Step 1 - 首先,准备一个名为 Data.xlsx 的 Excel,如下方的图片所示,包含以下数据 Ram ,以及 First NameLast Name 字段的 Ganesh 。将这个文件放在项目中的 TestData 文件夹下面。

selenium hybrid driven framework 4

Step 2 - 将环境值(比如应用程序的 URL)存储在文件 config.properties 中,其中包含 Configuration 文件夹下以键值对形式存储的数据。

baseUrl=https://www.tutorialspoint.com/selenium/practice/register.php

Step 3 - 创建一个配置文件 - log4j2.properties 文件。在此,我们将提供这些设置。创建一个文件,命名为 log4j2.properties ,放在 resources 文件夹下面。

log4j2.properties 文件中的配置。

name=PropertiesConfig
property.filename = logs
appenders = console, file

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

appender.file.type = File
appender.file.name = LOGFILE
appender.file.fileName=${filename}/LogsGenerated.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

loggers=file
logger.file.name=Logs
logger.file.level = debug
logger.file.appenderRefs = file
logger.file.appenderRef.file.ref = LOGFILE

rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

Step 4 - 创建实用程序文件,以访问测试用例中的 config.properties 文件和 Data.xlsx Excel 文件中的数据。我们将有 ReadingConfigValues.java 类文件来访问 config.properties 文件中的配置值,以及 ReadExcel.java 类文件来访问 Data.xlsx Excel 文件中的测试数据。这两个类文件都放在 utilities 包中。

Code Implementation

package utilities;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

public class ReadingConfigValues {
   Properties p;
   public ReadingConfigValues(){

      // loading properties file with file location
      File s = new File("./Configuration/config.properties");

      try {

         // getting the key value pair
         FileInputStream fileInputStream = new FileInputStream(s);
         p = new Properties();
         p.load(fileInputStream);
      } catch (Exception e){
         System.out.println("Exception encountered: " + e);
      }
   }
   public String getURL() {

      // get URL from .properties file
      String url = p.getProperty("baseUrl");
      return url;
   }
}

Code Implementation

package utilities;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;

public class ReadExcel {
   public ArrayList<String> readingExcel() throws IOException {
      int k;
      int l;

      // identify location of .xlsx file
      File f = new File("./TestData/Data.xlsx");
      FileInputStream i = new FileInputStream(f);

      // instance of XSSFWorkbook
      XSSFWorkbook w = new XSSFWorkbook(i);

      // create sheet in XSSFWorkbook with name Details1
      XSSFSheet s = w.getSheet("Details1");

      // get row and column numbers
      int r = s.getLastRowNum() + 1;
      int c = s.getRow(0).getLastCellNum();

      ArrayList<String> names = new ArrayList<>();

      // iterating through rows
      for (k = 1; k < r; k++) {
         Row rw = s.getRow(k);
         String name = "";

         // iterating through columns
         for (l = 0; l < c; l++) {
            Cell cell = rw.getCell(l);
            if("" != name){
               name += "," + cell.getStringCellValue();
            } else {
               name += cell.getStringCellValue();
            }
         }

         // storing excel values read to arraylist
         names.add(name);
      }

      // closing excel file
      w.close();
      return names;
   }
}

Step 5 - 在 pageObject 包中创建一个页面类 RegisterPage.java ,其中我们会放置 Web 元素,包括用于输入数据和针对那些元素执行操作的输入框。

package pageObjects;

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='firstname']")
   WebElement txtFname;

   @FindBy(xpath = "//*[@id='lastname']")
   WebElement txtLname;
   @FindBy(xpath = "//*[@id='signupForm']/div[5]/input")
   WebElement btnRegister;
   public RegisterPage(WebDriver driver) {
      this.driver=driver;

      // initializing all page objects
      PageFactory.initElements(driver, this);
   }
   public void inputFirstname(String fname) {
      txtFname.sendKeys(fname);
   }
   public void inputLastname(String lname) {
      txtLname.sendKeys(lname);
   }
   public void clickRegister() {
      btnRegister.click();
   }
   public String getFirstName(){
      return txtFname.getAttribute("value");
   }
   public String getLastName(){
      return txtLname.getAttribute("value");
   }
}

Step 6 - 在 TestNG.xml 中添加以下配置,其中包含能够在 Chrome 和 Edge 浏览器中执行测试用例的功能。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
   <test verbose="2" preserve-order="true" name="RegisterUser.java">
      <parameter name="browser" value="Chrome"></parameter>
      <classes>
         <class name="testCases.RegisterUserTest"></class>
      </classes>
   </test>
</suite>

Step 7 - 在 testCases 包中创建测试类 BaseClass.javaRegisterUserTest.java ,其中我们会编写实际的测试用例。

Code Implementation

package testCases;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import utilities.ReadingConfigValues;
import utilities.ReadExcel;

public class BaseClass {

   // reading values from external files
   ReadingConfigValues readingConfigValues = new ReadingConfigValues();
   ReadExcel readExcel = new ReadExcel();
   public String baseUrl = readingConfigValues.getURL();
   public static WebDriver driver;
   public static Logger logger;

   @BeforeClass
   @Parameters("browser")
   public void setup(String browser){
      logger = LogManager.getLogger(BaseClass.class);
      logger.info("Application Launched");

      // Initiate browser driver as per browser value
      if (browser.equalsIgnoreCase("Chrome")) {
         driver = new ChromeDriver();
         System.out.println("Browser opened in Chrome");
      } else if (browser.equalsIgnoreCase("Edge")) {
         driver = new EdgeDriver();
         System.out.println("Browser opened in Edge");
      }

      // launch application
      driver.get(baseUrl);
   }
   @AfterClass
   public void tearDown(){

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

Code Implementation

package testCases;

import org.testng.annotations.Test;
import pageObjects.RegisterPage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.assertTrue;

public class RegisterUserTest extends  BaseClass {
   @Test
   public void registerUser() throws IOException {
      logger.info("Reading values from excel from registration");

      // reading values of excel in arraylist
      ArrayList<String> result = readExcel.readingExcel();

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

      // object of RegisterPage page class
      RegisterPage registerPage = new RegisterPage(driver);
      logger.info("Starting registration");

      // input first and last name
      for (int i = 0; i <result.size(); i++) {
         String[] names = result.get(i).split(",");
         registerPage.inputFirstname(names[0]);
         registerPage.inputLastname(names[1]);
      }

      // click register button
      registerPage.clickRegister();
      logger.info("Verification of entered values");

      // verify value input in the first name
      if (registerPage.getFirstName().equalsIgnoreCase("Ram")){

         // assertions to test case
         assertTrue(true);
      } else {
         assertTrue(false);
      }

      // verify value input in the last name
      if (registerPage.getLastName().equalsIgnoreCase("Ganesh")){

         // assertions to test case
         assertTrue(true);
      } else {
         assertTrue(false);
      }
   }
}

Step 8 - 将以下依赖项添加到 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.apache.poi/poi -->
      <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi</artifactId>
         <version>5.2.5</version>
      </dependency>

      <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
      <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi-ooxml</artifactId>
         <version>5.2.5</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>
      <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-api</artifactId>
         <version>2.23.1</version>
      </dependency>
      <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>
         <version>2.23.1</version>
      </dependency>

      <!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
      <dependency>
         <groupId>com.aventstack</groupId>
         <artifactId>extentreports</artifactId>
         <version>5.1.1</version>
      </dependency>
   </dependencies>
</project>

Step 9 - 通过右键单击 TestNG.xml 文件,并选择选项 Run TestNG.xml,从该文件运行测试。

Output

Browser opened in Chrome
===============================================
All Test Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================

Process finished with exit code 0

在以上示例中,我们借助 TestNG 测试框架和页面对象模型设计模式,基于从 TestNG.xml 文件传递的 Chrome 参数在 Chrome 浏览器中创建了一个测试并启动了该应用程序。然后从 Data.xlsx 文件中获取测试数据,并在注册页面中的名字和姓氏字段中输入这些数据。

控制台中的结果显示为 Total tests run: 1 ,因为有一个带有 @Test 注释的 registerUser() 方法。

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

Step 10 − 刷新项目,一个名为 test-output 的新文件夹应该在项目结构中生成。

Step 11 − 右键单击 emailable-report.html 并选择在浏览器中打开的选项。

selenium hybrid driven framework 5

在浏览器中打开的报告显示测试类名称 - RegisterUser.java,其中包含通过、跳过、失败、测试持续时间等的总数。此外,测试方法名称 registerUser 也包括在报告中。

Conclusion

这总结了我们对 Selenium Webdriver 混合驱动框架教程的全面讨论。我们首先描述了为什么使用混合驱动框架,混合驱动框架有哪些优点、缺点以及基本组成部分,并通过一个示例演示了如何使用 Selenium Webdriver 实现混合驱动框架。

这使你具备了在 Selenium Webdriver 中混合驱动框架的深入知识。明智的做法是继续练习你所学到的知识,并探索与 Selenium 相关的内容,以加深你的理解并拓展你的视野。