[Java版]selenium关键字驱动框架设计实战(一)_职说测试-CSDN博客
关键字框架实现
前面已经带领大家认识了java反射,也演示了反射的调用示例,关键字的封装、更有关键字框架的代码实现;接下来就是对这个框架的具体实现进行封装。
读取Excel测试用例,需要用到poi工具包
<!-- excel读写工具包 -->
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
如何设计excel用例呢,首先1条用例是1个场景,实现场景的代码有很多,譬如:用户登录系统,进入某模块,发布1条消息。又要考虑一些场景:有些时候我并不想执行。这就是TestSuit和testcase的关系
看到上面的设计之后肯定又需要做进一步优化,因为在testsuit找到要执行的用例,需要去teststep中执行步骤,那么不是所有场景的用例都写在teststeps吧,那么变换一下,将testsuiteId作为teststep的sheet名
- 上面的意思就是找到suite页runmode为yes的testsuiteId,再去找到testsuiteId的sheet页,执行里面的操作步骤;作为一次循环;
- 先封装excel封装:读excel、获取sheet的行和列、读取关键的单元格数据,还有回写数据到excel指定sheet页的单元格
/**
*
* Todo:操作excel
*
* @author Joe-Tester
* @time 2021年8月27日
* @file ExcelUtils.java
*/
public class ExcelUtils {
public static hssfSheet ExcelSheet;
public static hssfWorkbook ExcelBook;
public static hssfRow Row;
public static hssfCell Cell;
/**
* 加载Excel
*
* @param Path
* :文件路径
*/
public static void setExcelFile(String Path) {
FileInputStream ExcelFile;
try {
ExcelFile = new FileInputStream(Path);
ExcelBook = new hssfWorkbook(ExcelFile);
} catch (FileNotFoundException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
/**
* 结果回写excel
*
* @param Result
* :执行结果回写
* @param RowNum
* :每次判断关键字的行号
* @param ColNum
* : 固定的结果列
* @param Path
* :文件路径
* @param SheetName
* :sheet页
*/
public static void setCellData(String Result, int RowNum, int ColNum,
String Path, String SheetName) {
try {
// 获取到excel的sheet表单
ExcelSheet = ExcelBook.getSheet(SheetName);
// 获取sheet表单的行数
Row = ExcelSheet.getRow(RowNum);
// 行+列确定单元格
Cell = Row.getCell(ColNum, MissingCellPolicy.RETURN_BLANK_AS_NULL);
// 结果写入,如果没有单元格则创建单元格
if (Cell == null) {
Cell = Row.createCell(ColNum);
Cell.setCellValue(Result);
} else {
Cell.setCellValue(Result);
}
// 这个操作其实是重新创建了一个excel
FileOutputStream fileOut = new FileOutputStream(Path);
ExcelBook.write(fileOut);
fileOut.flush();// 这个特别注意,需要刷新一下数据,相当于保存
fileOut.close();
} catch (Exception e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
/**
* 获取excel表格数据
*
* @param RowNum
* @param CloNum
* @param SheetName
* @return
*/
public static String getCellDate(int RowNum, int CloNum, String SheetName) {
ExcelSheet = ExcelBook.getSheet(SheetName);
Cell = ExcelSheet.getRow(RowNum).getCell(CloNum);
// 万一单元格出现int类型,获取却不是String,先设置其单元格值为String;或者在单元格写入数字前单引号'
Cell.setCellType(CellType.STRING);
String cellData = Cell.getStringCellValue();
return cellData;
}
/**
* 获取最后sheet最后一行
*
* @param SheetName
* @return
*/
public static int getLastRowNums(String SheetName) {
try {
ExcelSheet = ExcelBook.getSheet(SheetName);
int rowCount = ExcelSheet.getPhysicalNumberOfRows();
// getLastRowNum()+1;//最后一行行标,比行数小1
return rowCount;
} catch (Exception e) {
throw (e);
}
}
/**
*
* @param filePath
* @param sheetName
* @param picName
*/
public static void insertPicExcel(String filePath, String sheetName) {
FileOutputStream fileOut = null;
BufferedImage bufferImg = null;
// 先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
try {
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
bufferImg = ImageIO.read(new File(filePath));
ImageIO.write(bufferImg, "png", byteArrayOut);
hssfSheet testStepSheet = ExcelBook.getSheet(sheetName);
// 画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
hssfPatriarch patriarch = testStepSheet.createDrawingPatriarch();
// anchor主要用于设置图片的属性
hssfClientAnchor anchor = new hssfClientAnchor(0, 0, 255, 255,
(short) 1, 1, (short) 5, 8);
anchor.setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE); // setAnchorType(3)不支持这个数值了
// 插入图片
patriarch
.createPicture(anchor, ExcelBook.addPicture(
byteArrayOut.toByteArray(),
hssfWorkbook.PICTURE_TYPE_JPEG));
fileOut = new FileOutputStream(Contants.excelFile
+ Contants.excelName);
// 写入excel文件
ExcelBook.write(fileOut);
} catch (Exception e) {
e.printstacktrace();
} finally {
if (fileOut != null) {
try {
fileOut.close();
} catch (IOException e) {
e.printstacktrace();
}
}
}
}
}
然后再写操作excel的逻辑
/**
*
* Todo:这个类的处理逻辑是和Excel表格对应的,如果要更改Excel只需要改这个类,或者新增加一个和Excel对应的类
*
* @author Joe-Tester
* @time 2021年8月27日
* @file StartEngine.java
*/
public class StartEngine {
public static String Keywords = null;
public static String r;
public static boolean bResult;
public static void StartEngine(Object actionKeyWords) throws IOException {
// 初始化结果状态
bResult = true;
// 打开excel用例文件
ExcelUtils.setExcelFile(Contants.excelFile + Contants.excelName);
// 获取执行场景总行数
for (int j = 1; j < ExcelUtils.getLastRowNums(Contants.suitSheet); j++) {
// 是否需要执行
String caseStatus = ExcelUtils.getCellDate(j, Contants.suitRunmode,
Contants.suitSheet);
// 获取场景的id作为操作步骤的sheet
String testStepsSheet = ExcelUtils.getCellDate(j,
Contants.suitTestSuiteId, Contants.suitSheet);
int row;
// 遍历场景行数,判断是否需要执行
if (caseStatus.equals("YES")) {
Log.startTestCase("执行第" + j + "条用例:" + testStepsSheet);
// 遍历操作步骤的关键字及操作元素
// Log.info(suitTestSuiteId+",sheet页,最后一行的行号:"+ExcelUtils.getLastRowNums(suitTestSuiteId));
for (row = 0; row < ExcelUtils.getLastRowNums(testStepsSheet); row++) {
// 操作的关键字
String Keywords = ExcelUtils.getCellDate(row,
Contants.excelKWCloNum, testStepsSheet);
// 操作的页面元素
String r = ExcelUtils.getCellDate(row,
Contants.excelPOCloNum, testStepsSheet);
// 操作的值
String v = ExcelUtils.getCellDate(row,
Contants.excelVaCloNum, testStepsSheet);
// 调用关键字,注意suitTestSuiteId作为用例步骤的sheet页签的名字
Common_Engine.Action(Keywords, actionKeyWords, r, v, row,
bResult, testStepsSheet);
// 回写用例步骤页
if (bResult == false) {
ExcelUtils.setCellData(Contants.fail, j,
Contants.suitResult, Contants.excelFile
+ Contants.excelName,
Contants.suitSheet);
String destination = Screenshots.takeScreenshot(
KeywordsDriven.driver, "error");
ExcelUtils.insertPicExcel(destination, testStepsSheet);
}
}
Log.endTestCase("执行第" + j + "条用例:" + testStepsSheet + "结束!!!");
// 回写suit页
if (bResult == true) {
ExcelUtils.setCellData(Contants.pass, j,
Contants.suitResult, Contants.excelFile
+ Contants.excelName, Contants.suitSheet);
}
} else {
Log.info("当前用例:" + testStepsSheet + ",执行状态为:" + caseStatus
+ ",不执行!!!");
// 如果出现YES-NO-YES的用例场景,在第一个NO之后的YES或者NO都不执行
// break;
}
}
}
}
最后完善Common_Engine部分的关键字调用方法,通过关键字的类对象来进行反射调用
/**
*
* Todo:通用引擎,执行的是test steps关键字操作步骤,java反射获取关键字方法
*
* @author Joe-Tester
* @time 2021年8月27日
* @file Common_Engine.java
*/
public class Common_Engine {
// 日志收集器
// private static final Logger log =
// LogManager.getLogger(Common_Engine.class.getName());
/**
*
* @param Keywords
* :读取excel中关键字,判断是否在关键字对象中
* @param actionKeyWords
* :关键字对象
* @param element
* :关键操作对象的元素
* @param value
* :输入值
* @param rowNum
* : 操作步骤的行号
* @param bResult
* : 结果
* @param SheetName
* :执行场景步骤sheet页
*/
public static void Action(String Keywords, Object actionKeyWords,
String element, String value, int rowNum, boolean bResult,
String SheetName) {
// java反射获取类对象的所有方法
/* actionKeyWords= new Keywords_Driven(); */
Method[] method = actionKeyWords.getClass().getmethods();
// 遍历反射类对象
for (int i = 0; i < method.length; i++) {
// 判断获取对象的方法等于读取excel的关键字
if (method[i].getName().trim().equals(Keywords)) {
try {
// invoke调用关键字方法,字符串参数
method[i].invoke(actionKeyWords, element, value);
// Log.info("调用关键字<" + Keywords + ">方法.");
} catch (Exception e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
// 如果执行关键字方法回写用例执行步骤excel
if (bResult == true) {
ExcelUtils.setCellData(Contants.pass, rowNum,
Contants.testResult, Contants.excelFile
+ Contants.excelName, SheetName);
} else {
ExcelUtils.setCellData(Contants.fail, rowNum,
Contants.testResult, Contants.excelFile
+ Contants.excelName, SheetName);
}
break;
}
}
}
}
关键字的封装,按照excel的用例设计,每个关键字都只需要传入两个值,一个是操作元素,一个是值:function(locotor,value)
使用testng框架开始执行测试用例:
/**
*
* Todo: 用例演示
*
* @author Joe-Tester
* @time 2021年9月8日
* @file testExamlpe.java
*/
public class testExamlpe {
// 初始化关键字对象类
public static Object actionKeyWords;
/**
* 测试用例
*
* @throws IOException
*/
@Test(groups = { "p0" })
void KeywordsTestCase() throws IOException {
actionKeyWords = new KeywordsDriven();
StartEngine.StartEngine(actionKeyWords);
}
}
- 在这里testng框架在代码中可能没能提现出特别的优势,因为所有的用例都在一个excel里,所以也只需要一个测试方法;这对于testng来讲就是一个测试用例;
- testng还有用法,就是写xml文件组织用例:
<?xml version="1.0" encoding="UTF-8"?>
<suite name="precodition">
<!--platformName in {web ,android ,ios }-->
<!-- <parameter name="className" value="LoginKeyWords"/> -->
<test name="Web_Tests">
<groups>
<define name="p0">
<include name="p0" />
</define>
<run>
<include name="p0" />
<!--<exclude name="xxxx" />-->
</run>
</groups>
<classes>
<class name="selenium.keyword.testcase.testExamlpe"/>
</classes>
</test>
<listeners>
<!-- 添加ExtentRport监听 -->
<listener class-name="selenium.keyword.extenreports.MyExtentTestNgListener" />
</listeners>
</suite>
- 注意xml中有一个监听器:listener,这部分代码无论是po模式或是PageFactory模式,都是同一份报告模板,只是在关键字框架设计中有些不足,断言不完善,无法截图在报告中体现。
- 还有要强调日志收集,在执行过程中方便定位问题;引用了log4j,有两种用法,一种是在每个类单独使用,这样的好处log输出的位置是当前类的行,第二种是封装,这样的log输出的位置是封装后的行
// 第一种日志收集器
private static final Logger log = LogManager.getLogger(KeywordsDriven.class.getName());
// 第二种封装log4j
/**
*
* Todo:封装日志工具
*
* @author Joe-Tester
* @time 2021年9月10日
* @file Log.java
*/
public class Log {
private static Logger Log = Logger.getLogger(Log.class.getName());
// This is to print log for the beginning of the test case, as we usually
// run so many test cases as a test suite
public static void startTestCase(String sTestCaseName) {
Log.info("****************************************************************************************");
Log.info("****************************************************************************************");
Log.info("$$$$$$$$$$$$$$$$$$$$ " + sTestCaseName
+ " $$$$$$$$$$$$$$$$$$$$");
Log.info("****************************************************************************************");
Log.info("****************************************************************************************");
}
// This is to print log for the ending of the test case
public static void endTestCase(String sTestCaseName) {
Log.info("$$$$$$$$$$$$$$$$$$$$ " + sTestCaseName
+ " $$$$$$$$$$$$$$$$$$$$");
Log.info("****************************************************************************************\n");
}
// Need to create these methods, so that they can be called
public static void info(String message) {
Log.info(message);
}
public static void warn(String message) {
Log.warn(message);
}
public static void error(String message) {
Log.error(message);
}
public static void fatal(String message) {
Log.fatal(message);
}
public static void debug(String message) {
Log.debug(message);
}
}
testsuites执行结果:改名叫Scenarios场景,对应一个测试用例
总结
Java版selenium工具实现关键字框架设计,从关键字封装到反射调用关键字、从Excel操作封装到Excel测试用例设计、从测试报告到日志收集器,都一一进行了代码演示;欢迎各位指正!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。