Selenium 简明教程

Selenium - Hybrid Driven Framework

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

Selenium Webdriver can be used to develop test scripts which are based on the hybrid driven framework. A hybrid driven framework is a combination of a keyword driven and data driven framework. Thus, in a hybrid framework we incorporate the advantages of both the keyword driven and data driven frameworks.

Why Hybrid Framework is Used?

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

A hybrid framework is adopted to utilize essential features of both the keyword and data driven frameworks. It helps to make the test cases more flexible and individual features can exist independently without affecting the others. The test cases created with a hybrid framework are easier to maintain and addition of new test cases to this type of framework require less of time.

Advantages of Hybrid Framework

混合框架的优点如下 −

The advantages of hybrid framework are listed below −

  1. It is free and open source.

  2. Can be used across multiple platforms, browsers, and devices.

  3. Easy to maintain and scalable.

Disadvantages of Hybrid Framework

混合框架的缺点如下 −

The disadvantages of hybrid framework are listed below −

  1. Technical expertise is required to create a hybrid framework.

  2. It is difficult to port the test cases created using a hybrid framework to another application.

  3. Readability of test scripts can become challenging.

Basic Components of Hybrid Framework

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

The basic components of a hybrid framework are described in the below diagram −

selenium hybrid driven framework 1

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

As shown in the above diagram, the hybrid framework is divided into two phases - implementation and development phase, and the report generation phase. The report generation phase can be further extended to incorporate the continuous integration phase. For the continuous integration phase, we can take the help of Jenkins, and other tools along with Git(for version control of the code).

Example

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

Let us take an example of the below page where we would input the First Name as Ram and the Last Name as Ganesh then verify the values entered in the registration page using a hybrid framework.

selenium hybrid driven framework 2

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

Based on the diagram shown previously, we would create a project Hybrid and that would have the folders and packages developed to create a hybrid framework.

selenium hybrid driven framework 3

Prerequisites

  1. Install Java (version above 8) in the system and check if it is present with the command: java -version. The java version installed will be visible if installation has been completed successfully.

  2. Install maven in the system and check if it is present with the command: mvn -version. The maven version installed will be visible if installation has been completed successfully.

  3. Install any IDE like Eclipse, IntelliJ, and so on.

  4. Add the TestNG dependencies from the link TestNG.

  5. Add the Selenium Java dependencies from the link Selenium Java.

  6. Add the Log4j dependencies from the link Maven Artifacts.

  7. Add Apache POI Common dependencies from the link Apache POI Common.

  8. Add Apache POI API Based On OPC and OOXML Schemas dependencies from the link Apache POI API Based.

  9. Save the pom.xml with all the dependencies and update the maven project

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

Step 1 − First of all, prepare an excel called Data.xlsx as shown in the below image with the data Ram, and Ganesh for the First Name and the Last Name fields. Place this file under the TestData folder in the project.

selenium hybrid driven framework 4

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

Step 2 − Store the environment values like the application URL within the file config.properties which contains data in key-value pairs under the Configuration folder.

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

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

Step 3 − Create a configuration file - log4j2.properties file. Here, we would provide the settings. Created a file named log4j2.properties file under the resources folder.

log4j2.properties 文件中的配置。

Configurations in log4j2.properties file.

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 包中。

Step 4 − Create utility files to access the data from the config.properties file and Data.xlsx excel file in the test case. We would have the ReadingConfigValues.java class file to access the configuration values in the config.properties file and ReadExcel.java class file to access the test data in the Data.xlsx excel file. Both these class files were placed under the utilities package.

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 元素,包括用于输入数据和针对那些元素执行操作的输入框。

Step 5 − Create a page class RegisterPage.java under the pageObject package where we would have the web elements - input boxes to enter data and actions to be performed on those elements.

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 浏览器中执行测试用例的功能。

Step 6 − Add the below configurations in TestNG.xml with capabilities to execute the test cases in Chrome and Edge browsers.

<?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 ,其中我们会编写实际的测试用例。

Step 7 − Create test classes - BaseClass.java and RegisterUserTest.java under the testCases package where we would write the actual test case.

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 中。

Step 8 − The below dependencies added to 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,从该文件运行测试。

Step 9 − Run the test from the TestNG.xml file, by right clicking on it, and selecting the option 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 文件中获取测试数据,并在注册页面中的名字和姓氏字段中输入这些数据。

In the above example, we had taken help of the TestNG test framework and Page Object Model design pattern, to create a test and launched the application in the Chrome browser based on the Chrome parameter passed from the TestNG.xml file. Then obtained the test data from the Data.xlsx file and entered them in the First Name and Last Name fields in the registration page.

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

The result in the console shows Total tests run: 1, as there is one method with @Test annotation registerUser().

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

Finally, the message Passes: 1, and Process finished with exit code 0 was received, signifying successful execution of the code.

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

Step 10 − Refresh the project and a new folder called the test-output should get generated in the project structure.

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

Step 11 − Right-click on the emailable-report.html and select the option to open in a browser.

selenium hybrid driven framework 5

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

The report opened in the browser showing the test class name - RegisterUser.java with total number passed, skipped, failed, duration of test, and so on. Also, the test method name registerUser was also included in the report.

Conclusion

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

This concludes our comprehensive take on the tutorial on Selenium Webdriver Hybrid Driven Framework. We’ve started with describing why a hybrid driven framework is used, what are the advantages, disadvantages, and basic components of a hybrid driven framework, and walked through an example of how to implement a hybrid driven framework along with Selenium Webdriver.

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

This equips you with in-depth knowledge of the Hybrid Driven Framework in Selenium Webdriver. It is wise to keep practicing what you’ve learned and exploring others relevant to Selenium to deepen your understanding and expand your horizons.