《精通自动化测试框架设计》—第2章 2.6节使用数据库

    xiaoxiao2024-05-11  101

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

    2.6 使用数据库如果读者所在的企业正在招聘测试工程师或者读者正在求职,翻开工作说明书,无论是熟悉、掌握还是精通,估计绝大部分都会对于数据库有一定的要求。这说明了数据库在现在软件行业的普遍应用,也说明了这几乎是自动化测试所绕不开的一个技术点。在本小节中,将简要介绍如何通过编写代码与数据库进行交互。当然,这只是浅显的使用层面的介绍。如果牵涉到多套数据库数据配套不同用例集、基础数据导入以及数据清洗等问题,读者可以参考第1章中有关“快速回归测试系统”的介绍,以及下一小节中有关CSV文件的处理部分。因为各类型项目的挑战各不相同,本书给出的各种办法也仅供参考。读者需要结合自身的项目实际发现和解决各自的自动化问题。

    2.6.1 JDBC连接数据库即使是没有写过Java代码连接过数据库的读者,估计也都知道JDBC(Java Data Base Connectivity,Java数据库连接)和它的作用。JDBC对程序员而言是API,为程序开发提供标准的接口,通过这些用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。自从JDBC出现之后,就不必为访问Oracle数据库专门写一个程序,为访问MySQL数据库又专门写一个程序了。对实现与数据库连接的数据库厂商及第三方中间件厂商而言,JDBC则是接口模型,为实现与数据库的连接提供了标准方法。后者只要提供相应的驱动程序,提供给JDBC即可。数据库连接与操作一般都需要如下3个步骤。

    (1)提供驱动程序名,供JDBC加载对应的数据库驱动程序。

    (2)提供数据库连接串,从DriverManager中取得与数据库的连接。

    (3)在已经取得数据库连接对象Connection的基础上进行各种数据库操作。

    下面将介绍如何通过JDBC连接MySQL中TestLink数据库,并且从中完成查询。为了实现上述的前两个步骤,需要提供如下的一些信息。

    Driver="com.mysql.jdbc.Driver"; //驱动程序名URL="jdbc:mysql://localhost:3306/testlink"; //数据库连接串示例程序实现如下:

    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 DBDriver {     //TODO:put the params below to Configurator class & file     private static final String URL="jdbc:mysql://localhost:3306/testlink";     private static final String User="root";     private static final String Password="";     private static final String Driver="com.mysql.jdbc.Driver";     private static Connection conn;         public static Connection getConnection()     {      Connection connection=null;     if(conn!=null){        connection= conn;     }     else {        connection= getConnection(Driver,URL,User,Password);        conn=connection;     }     return connection;     }          public static Connection getConnection(String driver,String url,String      user,String password)     {        Connection conn=null;        try        {          Class.forName(driver);//load database driver          conn = DriverManager.getConnection(url, user, password);//create connection          System.out.println("New db conn created::"+conn.toString());        }        catch (Exception e) {          e.printStackTrace();        }            return conn;     }     public static void closeConnection(Connection con,Statement stm,ResultSet rs)     {         try        {           if(rs!=null)            rs.close(); //close resultset          if(stm!=null)            stm.close();//close statement          if(con!=null){            con.close();//close connection          System.out.println("Connection closed. Bye!");          }        } catch (SQLException e) {         throw new RuntimeException("Failed to close database!", e);      }      }     public static ArrayList select(String selectSql){     Statement stm = null;     ResultSet rs = null;     ResultSetMetaData rsmd =null;     ArrayList result=new ArrayList();     try {        stm = conn.createStatement();     rs = stm.executeQuery(selectSql);     rsmd = rs.getMetaData();     int cols=rsmd.getColumnCount();     ArrayList row=new ArrayList();     while (rs.next()){        row=new ArrayList();        for(int i=1;i< cols;i++){           if(null==rs.getString(i)){            row.add("");           }else {            row.add(rs.getString(i));          }        }     result.add(row);       }     } catch (SQLException e) {     e.printStackTrace();     } finally{        closeConnection(null,stm,rs);     }     return result;     }          public static void main(String [] args){     DBDriver.getConnection();     String sqlString="SELECT * FROM platforms ORDER BY id ASC";     ArrayList list=select(sqlString);       System.out.println("**********String to query::"+sqlString+"******************");     for(int i=0;i< list.size();i++){      System.out.println( list.get(i).toString());     }          sqlString="SELECT * FROM keywords ORDER BY id ASC ";     list=(ArrayList) select(sqlString);       System.out.println("**********String to query::"+sqlString+"******************");     for(int i=0;i< list.size();i++){      System.out.println( list.get(i).toString());     }      closeConnection(conn,null,null);        }        }

    在示例程序中,介绍了获取数据库连接的方法:

    getConnection(String driver,String url,String user,String password)通过传入不同的数据库驱动名称,就可以实现连接不同类型、不同实例的数据库。在实践中,一般通过读取配置文件来获取上述这些信息,避免了代码的重新编译与应用的部署。

    另外,这里也提供了一个便利的方法用于关闭数据连接等相关的对象实例。作为一个良好的编程习惯,在程序结束的时候一定要通过调用该方法完成相关资源的释放,否则会造成资源不足等问题。

    closeConnection(Connection con,Statement stm,ResultSet rs)这里并没有在select方法中调用closeConnection的时候关闭数据库连接。

    public static ArrayList select(String selectSql)通过程序的输出也可以看出,整个程序中只连接了一次数据库,而不是在每次的数据库操作中都需要重新连接数据库和关闭数据库连接,没有特别要求,只需重用即可。

    New db conn created::com.mysql.jdbc.JDBC4Connection@5c2445 **********String to query::SELECT * FROM 'platforms' ORDER BY 'id' ASC****************** [2, tpf_1409450867125, 19] [3, tpf_1409465605992, 19] [4, test111111, 107] [5, tpf_1414333517893, 114] [6, tpf_1414333737639, 114] **********String to query::SELECT * FROM 'keywords' ORDER BY 'keywords'.'id' ASC ****************** [2, k1, 19] [3, k2, 19] [4, k3, 19] [5, 123, 114] [6, 1234566, 114] [40, tpf_1416620840767, 125] Connection closed. Bye!

    2.6.2 使用Apache DbUtils在前一小节介绍了基本的JDBC使用之后,可能会觉得使用JDBC操作数据库并不难。但是需要细致与耐心,做许多繁琐且重复的工作,正如卖油翁所说,“无他,但手熟尔”。除了Spring等相对功能强大但学习成本较高、带有一整套架构理论的框架之外,还有一个适合自动化测试框架构建者的轻量级JDBC工具包,就是Apache基金会Apache Commons项目出品的DbUtils工具包。DbUtils封装了对JDBC的操作,简化了JDBC操作,却只有3个包,并且只依赖于JRE 1.6或以上的版本。该工具包可以从其官网下载,目前最新的版本是1.6。

    工具包的功能:org.apache.commons.dbutils——连接、关闭数据等常规操作。org.apache.commons.dbutils.handlers——对于ResultSet的操作。org.apache.commons.dbutils.wrappers——处理、修改ResultSet的一些特殊数据。

    1.org.apache.commons.dbutils该包中的主要类和功能如下。

    (1)DbUtils:该类提供了关闭连接、装载JDBC驱动程序之类的常规工作方法,并且这些方法都是静态的。

    ① close:DbUtils类提供了3个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是,就关闭连接、声明和结果集(ResultSet)。前面介绍的closeConnection方法就是借鉴了这种思想实现的。

    ② closeQuietly:如果不想捕捉使用close时抛出的诸如SQLEeception之类的异常,那么closeQuitely就是一个更好的选择。在调用handlers完成数据集的处理之后,在数据库操作的最后,只需要调用这一方法即可完成全部关闭操作。

    ③ loadDriver(String driveClassName):这一方法完成装载并注册JDBC驱动程序,如果注册成功就返回TRUE,否则返回FALSE。这样,就不再需要去捕捉注册驱动程序失败时所抛出的异常ClassNotFoundException,只需要根据返回的布尔值结果进行判断即可。

    (2)QueryRunner:简化了数据库的增删改查操作,用来替代JDBC中的executeQuery、executeUpdate等方法。通过与ResultSetHandler配合使用,能够大大减少所要写的代码。

    ① update:执行INSERT,UPDATE或者DELETE等SQL语句。

    ② insert:执行INSERT语句。

    ③ query:执行SELECT语句。

    另外,可以调用相关的batch方法来批量执行INSERT, UPDATE或者DELETE等SQL语句。

    (3)ResultSetIterator:该类实现了iterator接口,把一个ResultSet对象包装成一个迭代器。

    (4)ResultSetHandler:顾名思义,该接口执行处理一个结果集ResultSet对象,将数据转变并处理为任何一种形式,供其他应用使用。

    2.org.apache.commons.dbutils.handlers该包中的类都是对于前述ResultSetHandler的实现。

    (1)ArrayHandler:将ResultSet中第一行的数据转化成对象数组 。

    (2)ArrayListHandler:将ResultSet中所有的数据转化成List,List中存放的是Object[]。

    (3)BeanHandler:将ResultSet中第一行的数据转化成类对象。

    (4)BeanListHandler:将ResultSet中所有的数据转化成List,List中存放的是类对象。

    (5)ColumnListHandler:将ResultSet中某一列的数据存成List,List中存放的是Object对象。

    (6)KeyedHandler:将ResultSet中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。

    (7)MapHandler:将ResultSet中第一行的数据存成Map映射。

    (8)MapListHandler:将ResultSet中所有的数据存成List。List中存放的是Map。

    (9)ScalarHandler:将ResultSet中一条记录的某一列数据存成Object。

    3.org.apache.commons.dbutils.wrappers该包内有以下两个包装类。

    (1)SqlNullCheckedResultSet:该包装类用来对SQL语句执行完成之后的数值进行NULL的替换,并且可以根据需要替换成预设值,如N/A、-1等。

    (2)StringTrimmedResultSet :去除ResultSet中字段的左右空格,就是将ResultSet方法中的getString()和getObject()方法(如果获取的是String类型)获取的值,去除其前后空格,并将装饰过的ResultSet返回,供后续使用。

    2.6.3 从TestLink数据库中读取数据接下来,通过一个简单的案例来简要介绍如何使用DbUtils。当然在DbUtils官网上也提供了一些使用案例。感兴趣的读者可以通过以下网址进一步学习:

    http://commons.apache.org/proper/commons-dbutils/examples.html该示例将从TestLink数据库中读取平台表platforms,并且将结果借助于MapListHandler返回Map类型的数据集。

    package com.dataset.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.dbutils.DbUtils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.MapListHandler; public class DbUtil {   private static final String URL="jdbc:mysql://localhost:3306/testlink";   private static final String User="root";   private static final String Password="";   private static final String Driver="com.mysql.jdbc.Driver";   private static Connection conn;   public static Connection getConnection(){     Connection conn = null;     DbUtils.loadDriver(Driver);     try {       conn =DriverManager.getConnection(URL,User,Password);     } catch (SQLException e) {       e.printStackTrace();     }     return conn;   }   public static void main(String[]args) {     conn = getConnection();     QueryRunner qr = new QueryRunner();     List list = null;     String sqlString="SELECT * FROM `platforms` ORDER BY `id` ASC";     try {       list = qr.query(conn,sqlString, new MapListHandler());     Iterator ite = list.iterator();     while(ite.hasNext()){       Map map = (Map)ite.next();       System.out.println(map.toString());     }     } catch (SQLException e) {      // TODO Auto-generated catch block      e.printStackTrace();     }finally {      DbUtils.closeQuietly(conn);     }   }

    可以看到通过使用DbUtils可以较为方便地完成数据库的各项操作。并且通过配合MapListHandler,实现了结果集的类型转换。在2.5节中介绍的MockTestLinkAPI这个类的各个方法均使用了Map作为入参,两者如果配合使用,即可完成类似的从数据库中读取测试数据。按需转换后传递给测试执行API执行测试步骤的方案。除了MapListHandler,DbUtils还有其他如BeanListHandler、ArrayListHandler等进行数据集转换的类,可以配合不同的数据读取和处理的需求。读者可以根据实际项目的需要进行选择,这里就不赘述了。

    相关资源:精通Java Web整合开发(JSP AJAX Struts Hibernate)(第2版)
    最新回复(0)