美文网首页
Testng(三):加载外部数据

Testng(三):加载外部数据

作者: halfempty | 来源:发表于2018-11-12 13:30 被阅读0次

    1 概述

    对于一个函数或者一个流程,给定一个输入,应当返回一个结果

    输入指参数或条件的组合,也就构成不同的测试场景

    结果即程序对输入的处理,将其与预期结果比对,便可知当前测试场景功能的正确性

    当这些数据以外部文件的形式存储时,就可以很方便地修改追加,而不用重新调整代码

    2 @DataProvider

    在Testng中,@DataProvider负责向测试方法提供数据,返回Object[][]对象

    于是可以考虑,在@DataProvider方法中,实现读取外部文件,并将文件的内容以Object[][]形式返回

    方案:

    1. 每个方法对应各自的dataProvider,读取各自的数据文件;易于实现,但代码过于冗余,并且数据文件太零散,读频繁
    2. 所有方法对应一个dataProvider,dataProvider根据调用的方法名选择对应的测试数据;实现复杂,且需要考虑并行,但代码精简
    public class DataDriver {
        public static Map<String, Object[][]> data = null;
    
        @DataProvider(name = "dp")
        public static Object[][] getData(Method method) {
            if (data == null || data.get(method.getName()) == null) {
                return new Object[][] {};
            }
            return data.get(method.getName());
        }
    }
    

    这里选择第2种方式,但是并没有读外部文件,只提供按方法名选取数据

    考虑到测试用例过多,如果一次性将所有用例数据加载到内存,会过于臃肿,所以决定只加载当前case的数据

    3 TestCase

    @BeforeClass阶段初始化数据,@AfterClass阶段回收

    读取数据时,封装了工具类;根据不同的数据载体,可以编写多套工具类

    测试方法均指向同一个dataProvider,不要忘记加上dataProviderClass属性

    public class IpCase {
        @BeforeClass
        public void setup() {
            String caseFullName = this.getClass().getName();
            String caseName = caseFullName.substring(caseFullName.lastIndexOf('.') + 1);
            DataDriver.data = ExcelUtil.readExcel(caseName);
        }
    
        @AfterClass
        public void teardown() {
            DataDriver.data.clear();
        }
    
        @Test(dataProvider = "dp", dataProviderClass = DataDriver.class)
        public void isIpv41(String ip, boolean expected) {
            boolean actual = ip != null;
            Assert.assertEquals(actual, expected);
        }
    
        @Test(dataProvider = "dp", dataProviderClass = DataDriver.class)
        public void isIpv6(String ip, boolean expected) {
            boolean actual = ip != null;
            Assert.assertEquals(actual, expected);
        }
    }
    

    4 处理Excel文件

    数据存储,可以使用Excel,TXT,数据库也行,挑选一个易于维护、易于阅读的载体即可

    这里我们暂定为excel,使用poi包进行解析

    excel的名称要求与TestCase一致(IpCase.xlsx),且sheet名称对应各个测试方法(isIpv4, isIpv6),这样便可以根据方法名获取相应的测试数据

    isIpv4对应数据如下,首行为标题,解析时注意跳过

    IP Expected
    1.1.1.1 TRUE
    2.2.2.256 FALSE

    isIpv6对应数据如下

    IP Expected
    ::1 TRUE
    FF01::1101 TRUE
    public class ExcelUtil {
        private static final String SUFFIX_2007 = ".xlsx";
    
        public static Map<String, Object[][]> readExcel(String caseName) {
            Map<String, Object[][]> result = new HashMap<>();
            InputStream is = null;
    
            try {
                is = ExcelUtil.class.getClassLoader().getResourceAsStream(String.format("TestCase/%s%s", caseName, SUFFIX_2007));
                XSSFWorkbook workbook = new XSSFWorkbook(is);
    
                for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
                    Sheet sheet = workbook.getSheetAt(sheetNum);
    
                    int rows = sheet.getLastRowNum();
                    if (rows <= 0) continue;
                    int cols = sheet.getRow(1).getLastCellNum();
                    Object[][] data = new Object[rows][cols];
    
                    for (int rowNum = 1; rowNum <= rows; rowNum++) {
                        Row row = sheet.getRow(rowNum);
                        for (int celNum = 0; celNum < cols; celNum++) {
                            Cell cell = row.getCell(celNum);
    
                            Object cellValue = null;
                            CellType cellType = cell.getCellTypeEnum();
                            if (cellType == CellType.BOOLEAN) {
                                cellValue = cell.getBooleanCellValue();
                            } else if (cellType == CellType.STRING) {
                                cellValue = cell.getStringCellValue();
                            } else if (cellType == CellType.NUMERIC) {
                                cellValue = cell.getNumericCellValue();
                            } else {
                                cellValue = "";
                            }
    
                            data[rowNum - 1][celNum] = cellValue;
                        }
                    }
                    result.put(sheet.getSheetName(), data);
                }
            } catch (IOException e) {
                System.out.println("File not found: " + caseName);
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return result;
        }
    }
    

    5 @Test注解转换

    当测试方法需要加载数据时,都不得不指定属性dataProvider = "dp", dataProviderClass = DataDriver.class

    为了省事,可以使用IAnnotationTransformer监听器

    • 约定方法名包含“Dp”、“_dp”或其他你喜欢的后缀时,自动给@Test注解添加dataProvider属性
    • 指定group名,假设group = dp的测试方法均自动补充属性
    public class TestAnnotationTransformer implements IAnnotationTransformer {
        @Override
        public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
            String[] groups = annotation.getGroups();
            for(String group: groups) {
                if (group.equals("dp")) {
                    annotation.setDataProvider("dp");
                    annotation.setDataProviderClass(DataDriver.class);
                    break;
                }
            }
        }
    }
    

    6 后续优化

    • 目前只有excel解析工具类,且只支持2007版,可以补充2007以下版本支持
    • Excel数据类型判断,浮点数、日期等类型需要加强
    • 并行执行时,DataDriver.data可能冲突,需要将引用迁移到Case类下

    相关文章

      网友评论

          本文标题:Testng(三):加载外部数据

          本文链接:https://www.haomeiwen.com/subject/yeaqfqtx.html