Selenium 简明教程
Selenium - Hybrid Driven Framework
Selenium Webdriver 可用于开发基于混合驱动框架的测试脚本。混合驱动框架是关键字驱动框架和数据驱动框架的结合。因此,在混合框架中,我们结合了关键字驱动和数据驱动框架的优势。
Why Hybrid Framework is Used?
混合框架被采用来利用关键字和数据驱动框架的必要特性。它有助于使测试用例更灵活,并且各个特性可以独立存在,而不会影响其他特性。使用混合框架创建的测试用例更易于维护,并且向这种类型框架中添加新测试用例需要的时间更少。
Disadvantages of Hybrid Framework
混合框架的缺点如下 −
-
创建混合框架需要技术专长。
-
很难将使用混合框架创建的测试用例移植到另一个应用程序。
-
测试脚本的可读性可能成为一个挑战。
Basic Components of Hybrid Framework
混合框架的基本组件在以下图表中描述:
如上图所示,混合框架分为两个阶段:实施和开发阶段,以及报告生成阶段。报告生成阶段可以进一步扩展,加入持续集成阶段。对于持续集成阶段,我们可以借助 Jenkins 和其他与 Git(用于代码版本控制)一起使用的工具。
Example
让我们以以下页面的示例为例,其中我们会将 First Name 输入为 Ram ,将 Last Name 输入为 Ganesh ,然后使用混合框架验证在注册页面中输入的值。
根据先前所示的图表,我们会创建一个项目 Hybrid ,内容包括创建混合框架而开发的文件夹和包。
Prerequisites
-
在系统中安装 Java(高于 8 的版本)并使用命令检查其是否存在:java -version。如果安装已成功完成,将显示已安装的 Java 版本。
-
在系统中安装 maven 并使用以下命令检查它是否存在:mvn -version。如果已成功完成安装,将显示已安装的 maven 版本。
-
安装任何一个 IDE,例如 Eclipse、IntelliJ 等等。
-
从链接中添加 TestNG 依赖项 TestNG 。
-
从链接 Selenium Java 中添加 Selenium Java 依赖项。
-
从链接 Maven Artifacts 中添加 Log4j 依赖项。
-
从链接 Apache POI Common 中添加 Apache POI Common 依赖项。
-
从链接 Apache POI API Based 中添加 Apache POI API Based On OPC and OOXML Schemas 依赖项。
-
使用所有依赖项保存 pom.xml 并更新 Maven 项目
Step 1 - 首先,准备一个名为 Data.xlsx 的 Excel,如下方的图片所示,包含以下数据 Ram ,以及 First Name 和 Last Name 字段的 Ganesh 。将这个文件放在项目中的 TestData 文件夹下面。
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.java 和 RegisterUserTest.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: 1 和 Process finished with exit code 0 ,表示代码成功执行。
Step 10 − 刷新项目,一个名为 test-output 的新文件夹应该在项目结构中生成。
Step 11 − 右键单击 emailable-report.html 并选择在浏览器中打开的选项。
在浏览器中打开的报告显示测试类名称 - RegisterUser.java,其中包含通过、跳过、失败、测试持续时间等的总数。此外,测试方法名称 registerUser 也包括在报告中。