使用 TestNG 和 Excel 进行数据驱动测试

    使用 TestNG 和 Excel 进行数据驱动测试,测试完成后将测试结果写入Excel的数据文件最后一列。

    在D盘下,编辑“测试数据.xlsx”文件(注意扩展名必须是 .xlsx),编辑的文件内容如图所示:

    其中第1列为序号,第2列为测试用例名称,第3~6列是使用,测试数据,第7~9列是使用的测试数据,第10列表示此数据行是否需要在testing里面执行(y表示执行,n表示不执行),第11列显示测试执行的结果是否正确(在测试执行前将此列内容均填写为“/”,表示测试用例未被执行,执行成功后则会显示测试成功或者测试失败)

    ExcelUtil 类代码如下:

package cn.hx.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;

// 本类主要实现文件扩展名为.xlsx的Excel文件操作
public class ExcelUtil {
    private static XSSFSheet ExcelWSheet;
    private static XSSFWorkbook ExcelWBook;
    private static XSSFCell Cell;
    private static XSSFRow Row;

    // 设定要操作Excel的文件路径和Excel文件中的sheet名称
    // 在读/写Excel的时候,均需要先调用此方法,设定要操作的Excel文件路径和要操作的Sheet名称
    public static void setExcelFile(String filePath, String fileName, String sheetName) throws Exception {
        FileInputStream ExcelFile;
        try {
            // 实例化Excel文件的FileInputStream对象
            ExcelFile = new FileInputStream(filePath+"/"+fileName);
            // 实例化Excel文件的XSSFWorkbook对象
            ExcelWBook = new XSSFWorkbook(ExcelFile);
            // 实例化XSSFSheet对象,指定Excel文件中的sheet名称,后续用于sheet中行、列和单元格的操作
            ExcelWSheet = ExcelWBook.getSheet(sheetName);
        } catch (Exception e) {
            throw (e);
        }
    }

    // 读取Excel文件制定单元格的函数,只支持扩展名为.xlsx的Excel文件
    public static String getCellData(int RowNum, int ColNum) {
        try {
            // 通过函数参数指定单元格的行号和列号,获取指定的单元格对象
            Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
            @SuppressWarnings("deprecation")
            String CellData = Cell.getCellType() == XSSFCell.CELL_TYPE_STRING ? Cell.getStringCellValue() + ""
                    : String.valueOf(Math.round(Cell.getNumericCellValue()));
            return CellData;
        } catch (Exception e) {
            return "";
        }
    }

    // 在Excel文件的执行单元格中写入数据,只支持扩展名为.xlsx的Excel文件
        public static void setCellData(int RowNum, int ColNum, String Result) throws Exception {
        try {
            // 获取Excel文件中的行对象
            Row = ExcelWSheet.getRow(RowNum);
            // 如果单元格为空,则返回Null
            Cell = Row.getCell(ColNum, Row.RETURN_BLANK_AS_NULL);
            if (Cell == null) {
                // 当单元格的对象是Null时,则创建单元格
                // 如果单元格为空,无法直接调用单元格对象的setCellValue方法设定单元格的值
                Cell = Row.createCell(ColNum);
                // 创建单元格后可以调用单元格对象的setCellValue方法设定单元格的值
                Cell.setCellValue(Result);
            } else {
                // 单元格中有内容,则可以直接调用单元格对象的setCellValue方法设定单元格的值
                Cell.setCellValue(Result);
            }
            // 实例化写入Excel文件的文件输出流对象
            FileOutputStream fileOut = new FileOutputStream(Constant.FilePath+"/"+Constant.FileName); // 后续再改
            // 将内容写入Excel文件中
            ExcelWBook.write(fileOut);
            // 调用flush方法强制刷新写入文件
            fileOut.flush();
            // 关闭文件输出流对象
            fileOut.close();
        } catch (Exception e) {
            throw (e);
        }
    }

    // 从Excel文件获取测试数据的静态方法
    @SuppressWarnings("deprecation")
    public static Object[][] getTestData(String filePath, String fileName, String sheetName) throws IOException {
        // 根据参数传入的数据文件路径和文件名称,组合出Excel数据文件的绝对路径
        File file = new File(filePath + "/" + fileName);
        // 创建FileInputStream对象用于读取Excel文件
        FileInputStream inputStream = new FileInputStream(file);
        // 声明Workbook对象
        Workbook workbook = null;
        // 获取文件名参数的扩展名,判断是.xlsx文件还是.xls文件
        String fileExtensionName = fileName.substring(fileName.indexOf("."));
        // 判断文件类型如果是.xlsx,则使用XSSFWorkbook对象进行实例化
        // 判断文件类型如果是.xls,则使用SSFWorkbook对象进行实例化
        if (fileExtensionName.equalsIgnoreCase(".xlsx")) {
            workbook = new XSSFWorkbook(inputStream);
        } else if (fileExtensionName.equalsIgnoreCase(".xls")) {
            workbook = new HSSFWorkbook(inputStream);
        }
        // 通过sheetName参数生成Sheet对象
        Sheet sheet = workbook.getSheet(sheetName);
        // 获取Excel数据文件Sheet1中数据的行数,getLastRowNum方法获取数据的最后行号
        // getFirstRowNum方法数据第一行行号,相减之后算出数据的行数
        // 注意:Excel文件的行号和列号都是从0开始的
        int rowCount = sheet.getLastRowNum() - sheet.getFirstRowNum();
        // 创建名为records的list对象来存储从Excel数据文件读取的数据
        List<Object[]> records = new ArrayList<>();
        // 使用两个for循环遍历Excel数据文件的所有数据(除了第一行,第一行是数据列名称),所以i从1开始
        for (int i = 1; i < rowCount + 1; i++) {
            // 使用getRow方法获取行对象
            Row row = sheet.getRow(i);
            /*
             * 声明一个数组,用来存储Excel数据文件每行中的测试用例和数据,数组的大小用getLastCellNum-2来进行动态声明,
             * 实现测试数据个数和数组大小一致,因为Excel数据文件中的测试数据行的最后一个单元格为测试执行结果,倒数第二个单元格
             * 为测试数据是否执行的状态位,所以最后两列的单元格数据并不需要传入测试方法中,所以使用getLastCellNum-2去掉
             * 每行中的最后两个单元格数据,计算所要存储的测试数据个数,并做为测试数组的初始化大小
             */
            Object fields[] = new Object[row.getLastCellNum() - 2];
            // if用于判断测试数据是否要参与测试执行,Excel文件的倒数第二列为数据行的状态位,y执行,n跳过
            if (row.getCell(row.getLastCellNum() - 2).getStringCellValue().equals("y")) {
                for (int j = 0; j < row.getLastCellNum() - 2; j++) {
                    // 判断Excel的单元格字段使数字还是字符,字符串格式调用getStringCellValue方法获取
                    // 数字格式调用getNumericCellValue方法获取
                    fields[j] = (row.getCell(j).getCellType() == XSSFCell.CELL_TYPE_STRING
                            ? row.getCell(j).getStringCellValue()
                            : String.valueOf(Math.round(row.getCell(j).getNumericCellValue()))); }
// fields的数据对象存储到records的list当中 records.add(fields); } } // 定义函数返回值,即Object[][],将存储测试数据的list转换为一个Object二维数组 Object[][] results = new Object[records.size()][]; for (int i = 0; i < records.size(); i++) { results[i] = records.get(i); } return results; } public static int getLastColumnNum() { // 返回数据最后一列的列号,如果有12列,则返回11 return ExcelWSheet.getRow(0).getLastCellNum() - 1; } }

 

    TestNG 获取测试数据执行测试类,代码如下:

package cn.hx.testScripts;

import java.io.IOException;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import cn.hx.appModules.BandWideTest;
import cn.hx.appModules.BeforeLineLogin_Action;
import cn.hx.appModules.LineLogin;
import cn.hx.appModules.SelectTestType_Action;
import cn.hx.util.Constant;
import cn.hx.util.ExcelUtil;
import cn.hx.util.Log;
import cn.hx.util.SelectBrowser;
import junit.framework.Assert;

@SuppressWarnings("deprecation")
public class AutoLoginPublicSpTst {
    // 定义dataProvider,并命名为testData
    @DataProvider(name = "testData")
    public static Object[][] data() throws IOException {
        /*
         * 调用ExcelUtil类中的getTestData静态方法,获取Excel数据文件中倒数第二列标记为"y"的测试数据行,
         * 函数参数为常量Constant.TestDataExcelFilePath和常量Constant.
         * TestDataExcelFileSheet,指定数据文件的路径和Sheet名称
         */
        return ExcelUtil.getTestData(Constant.FilePath, Constant.FileName, Constant.TestDataExcelFileSheet);
    }

    @Test(dataProvider = "testData")
    public void testAuthLoginPubHttp(Object caseRowNum, Object testCaseName, Object browser, Object lineLoginType,
            Object testType, Object selectTestType, Object assWord1, Object assWord2, Object assWord3)
            throws Exception {
        Log.startTestCase((String) testCaseName);
        Log.info("启动WebDriver");
        Log.info("调用 SelectBrowser 类的 browserSelect 方法,启动 " + (String) browser + " 浏览器");
        // chrome--谷歌浏览器,firefox--火狐浏览器,ie--IE浏览器
        SelectBrowser.browserSelect(browser);
        Log.info("调用 BeforeLineLogin_Action 类的 execute 方法");
        Log.info("断言线路登录页面是否含关键字“"+assWord1+"”");
        try {
            BeforeLineLogin_Action.execute(SelectBrowser.driver, assWord1);
        } catch (AssertionError error) {
            Log.info("进入线路登录页面失败");
            ExcelUtil.setCellData(Integer.parseInt((caseRowNum.toString()).split("[.]")[0]), ExcelUtil.getLastColumnNum(), "执行失败");
            Assert.fail("执行 BeforeLineLogin_Action 类的 execute 方法失败");
        }
        Log.info("调用 LineLogin 类的 lineLogin_Action 方法");
        Log.info("断言选择测速项目类型页面是否含关键字“"+assWord2+"”");
        try {
            // manual--手动登录,automatic--自动登录
            // family--家庭用户,group--集团用户,other--其他用户
            LineLogin.lineLogin_Action(SelectBrowser.driver, lineLoginType, "", assWord2);
        } catch (AssertionError error) {
            Log.info("进入选择测速项目类型页面失败");
            ExcelUtil.setCellData(Integer.parseInt((caseRowNum.toString()).split("[.]")[0]), ExcelUtil.getLastColumnNum(), "执行失败");
            Assert.fail("执行 LineLogin 类的 lineLogin_Action 方法失败");
        }
        Log.info("调用 SelectTestType_Action 类的 testTypeSelect 方法");
        Log.info("断言测速页面是否含关键字“"+assWord3+"”");
        try {
            // bandWidth--宽带测速,surfExp--上网体验,lineMan--线务员测速
            SelectTestType_Action.testTypeSelect(SelectBrowser.driver, testType, assWord3);
        } catch (AssertionError error) {
            Log.info("进入测速页面失败");
            ExcelUtil.setCellData(Integer.parseInt((caseRowNum.toString()).split("[.]")[0]), ExcelUtil.getLastColumnNum(), "执行失败");
            Assert.fail("执行 SelectTestType_Action 类的 testTypeSelect 方法失败");
        }
        Log.info("调用 BandWideTest 类的 testTypeSel_Action 方法");
        BandWideTest.testTypeSel_Action(SelectBrowser.driver, selectTestType);
        Log.info("测速完成,在Excel的测试数据文件的“测试执行结果”列中写入“执行成功”");
        ExcelUtil.setCellData(Integer.parseInt((caseRowNum.toString()).split("[.]")[0]), ExcelUtil.getLastColumnNum(), "执行成功");
        Log.info("测试结果成功写入Excel数据文件的“测试执行结果”列");
        Log.endTestCase((String) testCaseName);
    }


    @BeforeClass
    public void beforeClass() throws Exception {
        ExcelUtil.setExcelFile(Constant.FilePath, Constant.FileName, Constant.TestDataExcelFileSheet);
    }

}

 

posted @ 2017-04-13 15:27  SunnyCC  阅读(525)  评论(0)    收藏  举报