Selenium Web 自动化 - 项目实战(二)
Selenium Web 自动化 - 项目实战(二)
2016-08-08
什么是数据驱动?简答的理解就是测试数据决定了测试结果,这就是所谓数据驱动。数据驱动包含了数据,他就是测试数据,在自动化领域里,提倡数据分离,也就是说,测试用例和测试数据是分开(存储)的。
在本框架设计中,采用的是Excel存储测试数据。
1 框架更改总览
在原来的框架下更改,如下图所示
2 框架更改详解
2.1 更改用例类:LoginPage_001_LoginSuccessFunction_Test.java
下面代码中,红色字体显示出更改前后变化。更改后数据不是写在代码中,而是从excel中读取。那么怎么让读取数据,且对应用例呢?
2.2 测试数据如何保存-设计excel
先看看如何设计excel:
excel的表名以模块名命名。excel中,有个sheet,名字为'001',对应用例编号,和设计用例的的类名第二部分是对应的,也就是说一个sheet就是一个测试用例的数据。在执行测试用例的时候,通过模块名字找到对应的excel,然后再根据对应的用例编号找到对应的sheet,最后在读取excel数据。
2.3 通过数据提供者获取测试数据
通过数据提供者(@DataProvider)来传递给测试用例,这里将数据提供者代码放置在BaseParpare.java中,目的是为了每次运行一个用例都会读取对应的测试用例。
/** * 测试数据提供者 - 方法 * */ @DataProvider(name = "testData") public Iterator<Object[]> dataFortestMethod() throws IOException { String moduleName = null; // 模块的名字 String caseNum = null; // 用例编号 String className = this.getClass().getName(); int dotIndexNum = className.indexOf("."); // 取得第一个.的index int underlineIndexNum = className.indexOf("_"); // 取得第一个_的index if (dotIndexNum > 0) { moduleName = className.substring(24, className.lastIndexOf(".")); // 取到模块的名称 } if (underlineIndexNum > 0) { caseNum = className.substring(underlineIndexNum + 1, underlineIndexNum + 4); // 取到用例编号 } //将模块名称和用例的编号传给 ExcelDataProvider ,然后进行读取excel数据 return new ExcelDataProvider(moduleName, caseNum); }
2.4读取Excel的方法
ExcelDataProvider.java,代码如下:
package com.demo.test.utils; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import jxl.Cell; import jxl.Sheet; import jxl.Workbook; import org.apache.log4j.Logger; import org.testng.Assert; /** * @author young * @description: 读取Excel数据<br> * 说明:<br> * Excel放在Data文件夹下<br> * Excel命名方式:测试类名.xls<br> * Excel的sheet命名方式:测试方法名<br> * Excel第一行为Map键值<br> */ public class ExcelDataProvider implements Iterator<Object[]> { private Workbook book = null; private Sheet sheet = null; private int rowNum = 0; private int currentRowNo = 0; private int columnNum = 0; private String[] columnnName; private String path = null; private InputStream inputStream = null; public static Logger logger = Logger.getLogger(ExcelDataProvider.class.getName()); /* * @description * 2个参数:<br> * moduleName - 模块的名称 * caseNum - 测试用例编号 **/ public ExcelDataProvider(String moduleName, String caseNum) { try { //文件路径 path = "data/" + moduleName + ".xls"; inputStream = new FileInputStream(path); book = Workbook.getWorkbook(inputStream); // sheet = book.getSheet(methodname); sheet = book.getSheet(caseNum); // 读取第一个sheet rowNum = sheet.getRows(); // 获得该sheet的 所有行 Cell[] cell = sheet.getRow(0);// 获得第一行的所有单元格 columnNum = cell.length; // 单元格的个数 值 赋给 列数 columnnName = new String[cell.length];// 开辟 列名的大小 for (int i = 0; i < cell.length; i++) { columnnName[i] = cell[i].getContents().toString(); // 第一行的值 // 被赋予为列名 } this.currentRowNo++; } catch (FileNotFoundException e) { logger.error("没有找到指定的文件:" + "[" + path + "]"); Assert.fail("没有找到指定的文件:" + "[" + path + "]"); } catch (Exception e) { logger.error("不能读取文件: [" + path + "]",e); Assert.fail("不能读取文件: [" + path + "]"); } } /**是否还有下个内容*/ public boolean hasNext() { if (this.rowNum == 0 || this.currentRowNo >= this.rowNum) { try { inputStream.close(); book.close(); } catch (Exception e) { e.printStackTrace(); } return false; } else { // sheet下一行内容为空判定结束 if ((sheet.getRow(currentRowNo))[0].getContents().equals("")) return false; return true; } } /**返回内容*/ public Object[] next() { Cell[] c = sheet.getRow(this.currentRowNo); Map<String, String> data = new HashMap<String, String>(); for (int i = 0; i < this.columnNum; i++) { String temp = ""; try { temp = c[i].getContents().toString(); } catch (ArrayIndexOutOfBoundsException ex) { temp = ""; } data.put(this.columnnName[i], temp); } Object object[] = new Object[1]; object[0] = data; this.currentRowNo++; return object; } public void remove() { throw new UnsupportedOperationException("remove unsupported."); } }
Pom.xml添加jar依赖:
<dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version> <scope>provided</scope> </dependency>