《精通自动化测试框架设计》—第2章 2.7节使用CSV文件

    xiaoxiao2024-05-08  6

    本节书摘来自异步社区《精通自动化测试框架设计》一书中的第2章,第2.7节使用CSV文件,作者陈冬严 , 邵杰明 , 王东刚 , 蒋涛,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    2.7 使用CSV文件CSV[1]的全称是Comma Separate Values,即以逗号为分隔符,每条记录占一行的一种文件格式。当然分隔符并不限制于逗号,因此其另一个名字叫做Character Separated Values。这种古老的文件格式早在20世纪60年代就已出现,被使用于IBM OS360上,远早于个人电脑时代的来临。时至今日,CSV文件依然顽强并且广泛地使用着,特别是在程序间交换数据的场合。例如,在某些ERP系统中,作为安装的一部分,在完成了二进制可执行文件的安装之后,需要导入一些基础数据,如工作流的定义、各种对象的定义与属性、变更流程定义等。这些很多时候是使用CSV格式的文件进行的交互。另外,用户列表、组织权限、产品列表等产品使用或者示例的数据等,也是如此。

    在进行自动化测试时,测试用例中的数据非常依赖于AUT中的上下文基础数据,而这些基础数据又可以通过CSV文件导入到AUT之中。那么,考虑将这些CSV文件中遴选出部分必需的数据,导入到测试框架中,作为测试框架的基础数据存在并供下游用例使用。据此,则可简单实现所谓的单一数据源(Single Source Of Truth),即使后期CSV文件中的变化了,因为用例和被测应用使用同一套数据源,自动化测试也可以照常执行。这种设计既提高了数据通用性,又降低了维护成本。

    2.7.1 CSV文件数据解析思路从面向对象的角度,如果将一个CSV文件的记录结构类比成一个Java类,那么该CSV文件中的每一条记录就可以理解为同一个类的不同实例,它们有着相同的属性,当然属性值随着记录数据的不同而不同。因此,与通过xstream将XML文件转换成Java对象类似,通过将CSV文件导入并转换成Java对象,然后按照操纵对象的方式来处理CSV文件中的数据,从而避免了通过I/O,反复处理文件操作这种费时费力的方式。熟悉数据库开发的读者可能对这种方式很熟悉,这其实就是借助了数据库中常用的对象关系映射(ORM, Object/Relation Mapping)概念。感兴趣的读者可以查阅相关的资料进行学习。

    提供了将CSV文件转换为Java对象的第三方工具包比较多,这里采用的是opencsv。这一工具包的作者是Glen Smith,目前的维护者是Sean Sullivan。整个项目还处在积极的维护当中。在此小节写成的这一周,其官方网站上的单周下载量超过了1000次。另外其采用的是Apache 2.0 许可模式,只要不对它进行修改,即使用于商业用途,也是免费的。当然这一工具除了进行CSV到Java对象的转换,其余的功能如CSV导入导出功能也是比较全的。需要进行更多的CSV操作的读者可以到其官网上详细了解其他功能。

    2.7.2 实现泛型解析Opencsv提供了非常方便的CSV文件解析方法。在此基础上加以简单的封装,就可以实现一个较为通用的CSV文件转换为Java对象的方法。核心代码如下:

       public static< T extends BaseBean > List< T > parseCSV2Bean (String filename,Class< T > type){      List< T > list =null; try { CSVReader reader = new CSVReader(new FileReader(filename), ',', '\"'); //构造了一个CSV文件的解析器,待解析的CSV文件以逗号分隔记录中的字段,以双引号作为各字段的起止标志。 HeaderColumnNameMappingStrategy< T >mappingStrategy = new HeaderColumnNameMappingStrategy< T >();     //HeaderColumnNameMappingStrategy实现了MappingStrategy接口,这种匹配策略下会将 //文件第一行的每个字段作为待转换的bean类的成员变量,也就是其属性 mappingStrategy.setType(type);     //此处通过泛型实现了待解析文件和与之对应的Java Bean类之间的动态匹配 CsvToBean< T > csv = new CsvToBean< T >(); list = csv.parse(mappingStrategy, reader);     //完成解析,并将解析的结果返回给一个泛型的list      } catch (FileNotFoundException e) { e.printStackTrace();      } return list;   }

    至此,通过一段简短的代码,就实现了通用的CSV转换为Java Bean list的功能。当然有一个小窍门就是,所有的Java Bean类都需要继承BaseBean。

    2.7.3 对象类案例下面是一个简单的示例。假设有一个employee.csv的员工信息表,与之对应的是一个EmployeeBean的类,其成员变量可以是id,name,position,salary等,如下面的代码所示:

    public classEmployeeBean { private intid; private String name; private String role; private String salary; //其余get/set方法省略 }

    通过下面的这两行代码,就可以实现两者之间的解析和匹配的工作。

    List< EmployeeBean > employees; employees=CSVDigester.parseCSV2Bean("employee.csv",EmployeeBean.class)

    解析得到的结果将返回给一个List employees的变量。据此,如本小节开头所介绍的那样,将繁琐的文件操作转换成了对一个list的访问,简化了操作,提高了速度,并增强了系统鲁棒性。

    2.7.4 提供数据源的外部访问

    Public classBeans { private static List < EmployeeBean >employees; public static voidsetEmployees(List < EmployeeBean > employees) {   Beans.employees = employees; } public static List< EmployeeBean >getEmployees() {   returnemployees; }//提供该Employee数据源的外部访问接口 static {    setEmployees(CSVDigester.parseCSV2Bean("employees.csv",EmployeeBean.class)); //测试框架初始化时读入该数据 }

    如果有其他的CSV文件需要解析,则在Beans的静态块中使用类似操作即可。通过以上的操作,已经将针对CSV文件的操作转换成了对List employeeBeans的操作。使用时,直接采用以下语句:

    Beans.getEmployees();既提供了静态方法,也方便了数据的使用。

    通过有针对性地将一些通用的操作封装成方法,简化测试用例的自动化实现和代码的复用性,譬如查询某个employee是否存在等。具体的代码例子这里不再列举,读者可以自行实现。

    2.7.5 CSV文件通过SQL方式查询结果CSV文件还可以通过SQL查询的方式通过JDBC进行读取。以2.6.3中所介绍的读取TestLink数据库中的表platforms为例。如果将该表导出到一个CSV当中,则可以将前述的案例程序稍加改动,将driver以及Connection的取得方式更换成CSV文件方式即可,具体程序如下:

    package com.dataset.db;   import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List;   public class CSVDriver {     private static String filepath="D:\\repo\\Playground";     private static final String URL="jdbc:relique:csv:" + filepath;   private static final String Driver="org.relique.jdbc.csv.CsvDriver";     private static Connection conn;     public static Connection getConnection()     {         Connection connection=null;         if(conn!=null){          connection= conn;     }       else {          connection= getConnection(Driver,URL);          conn=connection;         }         return connection;     }          public static Connection getConnection(String driver,String url)     {       Connection conn=null;       try       {         Class.forName(driver);//driver来源已经修改为CSV驱动器         conn = DriverManager.getConnection(url);//连接也已经使用了重载的方法,单以            URL为入参       System.out.println("New db conn created::"+conn.toString());       }       catch (Exception e) {         e.printStackTrace();       }              return conn;     }     //以下closeConnection、select方法与之前无异,略     public static void main(String [] args){      //main方法中无任何变化      }

    这个程序运行完毕后,如果输入的数据内容相同,那么可以得到与之前相同的输出结果。这种方式为基础数据的参数化提供了便利,在数据库中完成开发之后,可以将结果导出为CSV,供用例集运行时作为初始基础数据使用。毕竟如本书第1章中所介绍的“快速回归系统”,在测试执行过程中,一遍遍清洗数据库是一个耗时耗力的事情,至少包括数据库的停止、清洗、导入和开启。而将不同的数据集导出为CSV文件,不同的测试集通过使用不同的CSV文件目录作为数据源,可以大大减轻其中的复杂程度。

    本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)