数据驱动框架(Apache POI – Excel)
你是否难以维护应用程序的大量测试用例?测试数据是否分散在各种测试脚本中?您是否必须为每个测试环境维护单独的测试脚本,然后在测试数据中一个值发生更改的情况下在所有脚本中进行搜索?这很费时间,很费力,不是吗?我们都希望测试用例是一致的,并以统一的方式编写,遵循一组规则,例如我们有交通规则,并且每个人在路上都尝试遵循相同的规则。这就是数据驱动框架起作用的地方。
自动化测试框架是用于创建和设计测试用例的一组准则或规则。该准则包括编码标准,对象存储库,测试数据处理方法,存储测试结果的过程或有关如何访问外部资源的任何其他信息。
测试人员可以始终在没有框架的情况下编写测试,这不是必需的步骤,但是使用组织化的框架还可以带来其他好处,例如增加代码重用,更高的可移植性,降低的脚本维护成本以及更高的代码可读性。它还可以帮助团队以标准格式写下测试脚本。使用自动化测试框架,可以高效地设计和开发自动化测试脚本,并确保可靠地分析受测系统或应用程序的问题或错误。以下部分列出了一些重要的优点,这些优点证明了对自动化测试框架的需求是合理的:
使用自动化测试框架非常重要,因为它可以提高自动化测试团队的效率和测试开发速度。使用自动化框架的一些好处如下:
所有测试的标准格式
提高测试效率
降低脚本维护成本
最大测试范围
代码的可重用性
高效的测试数据管理
使用Selenium WebDriver测试应用程序时,可以使用三种主要类型的框架为任何Web应用程序创建自动化测试:
数据驱动测试框架。
关键字驱动的测试框架。
混合测试框架。
这些框架中的每一个都有其自己的体系结构以及不同的优缺点。在制定测试计划时,重要的是要选择适合您的框架。
数据驱动测试框架 用于将测试脚本与测试数据分开。您可以使用多组数据测试同一脚本。我们将在以下主题中详细讨论此框架。
关键字驱动测试框架 是数据驱动框架的扩展。它允许在测试脚本外部将一组称为“关键字”的代码存储在单独的代码文件中。我们可以在多个测试脚本中重复使用这些关键字。
混合驱动框架 是数据驱动框架和关键字驱动框架的组合。在这里,关键字以及测试数据都是外部的。我们在单独的文件中维护关键字,并在excel文件或CSV文件或数据库中测试数据。
在本文中,让我们深入研究数据驱动测试框架。
通常,当我们手动测试应用程序时,我们针对多个测试数据运行相同的方案。此外,我们将相同的测试数据保存在某些文件中,例如Excel文件,文本文件,CSV文件或任何数据库。自动化也是如此,我们希望对多个测试数据运行相同的测试方案。假设您已经写了一个自动化脚本来填写
ToolsQA Demo网站上的学生注册表格。可能有很多学生要注册,唯一区别在于代码的是输入值(姓名,地址,电话,性别等)。您会为每个学生注册一个单独的脚本吗?有没有办法,我们可以重用代码并仅更改学生数据?
是的,这是数据驱动框架发挥作用的地方,它可以使测试脚本针对不同的测试数据集正常工作。这样可以节省编写其他代码的时间。这就像一次编写并多次运行的机制一样,因为您可以多次运行相同的Selenium脚本。
简而言之,当我们必须使用多组测试数据执行相同的脚本时,就使用数据驱动框架,这些测试数据的存储位于不同的位置,并且不在测试脚本内。对数据所做的任何更改都不会影响测试代码。
以下是质量保证人员在使用数据驱动技术开发自动化框架时可以从中获得的一些主要好处:
无需修改代码即可修改测试用例。
它允许使用多组数据值测试应用程序,尤其是在回归测试期间。
它帮助我们从测试数据中分离出测试用例/脚本的逻辑。
该测试最常用的数据源之一是Microsoft Excel Sheets。我们可以将数据保留在excel工作表中,并在测试脚本中使用它们。让我们看看如何通过从Excel文件读取测试数据来创建数据驱动的UI自动化框架。
如何使用Apache POI在Selenium中创建数据驱动框架?
从Selenium中的Excel中读取和写入数据”中学到了如何使用Apache POI在Excel文件中读取和写入数据,然后将与测试数据相同的数据集传递给Selenium测试。但是在该脚本中,从Excel文件读取数据,将数据写入Excel文件,将数据传递给Selenium操作的所有动作都发生在该类的main方法中。如果我们仅编写一个或两个测试用例,则该格式是可以接受的。但是,当我们必须开发一个具有多个测试方案的自动化框架时,它应该适当地组织并且应该具有定义的文件夹层次结构。
数据驱动测试框架的基本经验法则是将测试数据与测试脚本分开。此外,从文件读取/写入数据的操作应分开进行,并且可以作为实用程序使用。
请按照下面提到的步骤创建一个基本的数据驱动框架,该框架将用于自动执行“学生注册表“。
在您的项目中为testCases,testData和Utility创建三个New Packages。”。
在testData包下,将具有测试数据的Excel工作表放入。使用此方法,我们将测试数据与testCases分开。
在实用程序下,创建一个新类,并将其命名为“ ExcelUtils ”。它将包含与Excel有关的所有用于读写的功能。
在实用程序包下,创建另一个类“ Constants”。它将包含跨框架的常量值,例如testdata文件路径,应用程序的URL等。
在testCases包下,我们将创建包含用于与Web元素交互的Selenium代码的测试文件。(例如,RegisterStudentTest.java)
完成上述步骤后,文件夹结构将如下所示:
让我们了解每个类的详细信息:
1. ExcelUtils类–这是一个实用程序类,它将包含与Excel Sheet读写操作以及初始化工作簿有关的所有方法。然后,您可以通过创建Excel Utils类的对象在不同的测试用例中重用这些方法。该类的代码如下:
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ExcelUtils {
private static HSSFWorkbook workbook;
private static HSSFSheet sheet;
private static HSSFRow row;
private static HSSFCell cell;
public void setExcelFile(String excelFilePath,String sheetName) throws IOException {
//创建一个File类的对象来打开xls文件
File file = new File(excelFilePath);
//创建FileInputStream类的对象以读取excel文件
FileInputStream inputStream = new FileInputStream(file);
//正在创建引用.xls文件的工作簿实例
workbook=new HSSFWorkbook(inputStream);
//创建图纸对象
sheet=workbook.getSheet(sheetName);
}
public String getCellData(int rowNumber,int cellNumber){
//从rowNumber和cell Number获取单元格值
cell =sheet.getRow(rowNumber).getCell(cellNumber);
//以字符串形式返回单元格值
return cell.getStringCellValue();
}
public int getRowCountInSheet(){
int rowcount = sheet.getLastRowNum()-sheet.getFirstRowNum();
return rowcount;
}
public void setCellValue(int rowNum,int cellNum,String cellValue,String excelFilePath) throws IOException {
//在行中创建新单元格并为其设置值
sheet.getRow(rowNum).createCell(cellNum).setCellValue(cellValue);
FileOutputStream outputStream = new FileOutputStream(excelFilePath);
workbook.write(outputStream);
}
}
上面的代码包含不同的方法,例如setExcelFile 初始化Excel 工作簿,getCellValue 检索文件中特定单元格中存在的值,setCellValue 设置一些值到新创建的单元格中。以类似的方式,您可以在此类中创建与excel操作相关的不同方法。
2.常量类–用于将常量值放在文件中,以便可以在测试用例中重复使用它们。将值放置在单独的文件中的另一个优势是,如果这些值在任何测试中都是通用的,那么如果其中的任何值有任何更改,则只需要在一个位置进行更新即可。例如,如果文件路径已更改,则无需使用新值更新所有测试用例,而只需在一个文件中对其进行更新。 此类中的结构和值如下所示–
package utilities;
public class Constants {
public static final String URL = "https://demoqa.com/automation-practice-form";
public static final String Path_TestData = "E:\\Projects\\src\\testData\\";
public static final String File_TestData = "TestData.xls";
3. RegisterStudentTest –这是学生注册表的测试脚本,我们用于输入特定学生的名字,姓氏,手机,电子邮件,性别等。由于我们现在已经将与excel相关的方法分离在一个单独的文件中,因此测试用例的代码也会更改。
我们将在此测试文件中创建ExcelUtils 类的对象,并使用常量 引用文件的路径。
更新后的代码现在看起来像–
package testCases;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import utilities.Constants;
import utilities.ExcelUtils;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class RegisterStudentTest {
//创建ExcelUtils类的对象
static ExcelUtils excelUtils = new ExcelUtils();
//将常量类值用于excel文件路径
static String excelFilePath =Constants.Path_TestData+Constants.File_TestData;
public static void main(String args[]) throws IOException {
//设置Chrome驱动程序路径
System.setProperty("webdriver.chrome.driver","E:\\Projects\\chromedriver.exe");
//创建ChromeDriver对象
WebDriver driver = new ChromeDriver();
//启动指定的URL
driver.get("https://demoqa.com/automation-practice-form");
//确定学生登记表的WebElements
WebElement firstName=driver.findElement(By.id("firstName"));
WebElement lastName=driver.findElement(By.id("lastName"));
WebElement email=driver.findElement(By.id("userEmail"));
WebElement genderMale= driver.findElement(By.id("gender-radio-1"));
WebElement mobile=driver.findElement(By.id("userNumber"));
WebElement address=driver.findElement(By.id("currentAddress"));
WebElement submitBtn=driver.findElement(By.id("submit"));
//调用ExcelUtils类方法初始化工作簿和工作表
excelUtils.setExcelFile(excelFilePath,"STUDENT_DATA");
//遍历所有行以打印每个单元格中的数据。
for(int i=1;i<=excelUtils.getRowCountInSheet();i++)
{
//在firstname、lastname、mobile、email、address中输入从Excel读取的值
firstName.sendKeys(excelUtils.getCellData(i,0));
lastName.sendKeys(excelUtils.getCellData(i,1));
email.sendKeys(excelUtils.getCellData(i,2));
mobile.sendKeys(excelUtils.getCellData(i,3));
address.sendKeys(excelUtils.getCellData(i,4));
//使用javascript单击gender单选按钮
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", genderMale);
//单击“提交”按钮
submitBtn.click();
//验证确认消息
WebElement confirmationMessage = driver.findElement(By.xpath("//div[text()='Thanks for submitting the form']"));
//检查是否显示确认消息
if (confirmationMessage.isDisplayed()) {
// 如果显示消息,则使用excel方法在excel表中写入PASS
excelUtils.setCellValue(i,6,"PASS",excelFilePath);
} else {
//如果未显示消息,请使用excel方法在excel表中写入FAIL
excelUtils.setCellValue(i,6,"FAIL",excelFilePath);
}
//close the confirmation popup
WebElement closebtn=driver.findElement(By.id("closeLargeModal"));
closebtn.click();
//单击“关闭”按钮后,等待页面返回注册页面
driver.manage().timeouts().implicitlyWait(2000,TimeUnit.SECONDS);
}
//关闭驱动程序
driver.quit();
}
}
但是,如果您注意到,ExcelUtils的方法将 处理所有与excel相关的代码。
因此,这是在Selenium中使用数据驱动框架的方法之一。此外,您可以利用在多组数据上运行相同测试的优势。