DBCompare小工具研发

作者: Tomandy | 来源:发表于2018-03-09 16:45 被阅读100次

      测试过程中,经常涉及到数据库表记录的检查,比如案例执行完成后,需检查某几张表insert,update或delete是否正确。面对此类测试场景,测试人员一般都是交易前后分别把表记录导出,然后再做比对检查表记录是否正确。这种测试方法存在两个问题:

    1、操作繁琐。
    2、表记录过多时,纯靠眼力检查容易出错。

      针对以上问题,我们稍微转换一下思路,让工具来简化测试工作,提升测试效率及准确度。下面笔者将以oracle数据库为例,详述DBCompare小工具的研发过程。
      首先,笔者将工具的使用方法做简单描述,然后再跟各位分享工具的实现思路及相关代码。

    数据比对工具.png
      上图为小工具的界面展示,“环境”配置在config.properties文件,配置信息为用户名、密码、ip及端口信息,可灵活配置各个环境参数,如下图所示。
    环境配置.png
      选择环境,填写表名,然后获取索引;
    (1)“输入索引”为选输框,获取索引失败的话,可手工输入索引;
    (2)“查询条件”为选输框,如果“查询条件为空”,则查询全表记录作比较;否则只获取符合查询条件的记录作比较;
    (3)点击“交易前查询”按钮;
    (4)执行交易或测试脚本;
    获取索引.png
    交易前查询.png
    (5)点击“交易后查询”按钮,自动打开交易前后比对文件。
    • 对于交易前和交易后都存在的记录,根据索引比对各字段是否一致,不一致的字段标注红色;
    • 对于交易前存在记录,交易后不存在记录(删除),标准玫瑰色;
    • 对于交易前不存在记录,交易后存在记录(新增),标准红色;
      交易前后记录比对文件.png
      交易前后记录比对文件.png
        以上就是工具的简单描述,接下来咱们来聊聊工具实现的思路。
    • 读取环境配置;
        /*
         * 获取环境配置信息
         */
        public static Map<String, String> getEnv() {
            Map<String, String> env_map = new HashMap<String, String>();
            InputStream in = null;
            Properties p = new Properties();
            try {
                in = new BufferedInputStream(new FileInputStream("config\\"
                        + "config.properties"));
                p.load(in);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Enumeration<Object> keys = p.keys();
            while (keys.hasMoreElements()) {
                String key = (String) keys.nextElement();
                env_map.put(key, p.getProperty(key));
            }
            System.out.println("env_map: " + env_map);
            return env_map;
        }
    
    • 链接数据库;
    /*
         * 链接数据库
         */
        // @SuppressWarnings("finally") String env,String user,String password
        public static Connection oracle() {
            try {
                /*
                 * 获取环境参数
                 * upi[0]=用户名;
                 * upi[1]=密码;
                 * upi[2]=IP地址;
                 */
                String usPassIp = envVar_map.get(comBoxItem).trim(); //获取用户名,密码,ip
                String upi[] = usPassIp.split(",");// 分割字符串得到数组
                for (int i = 0; i < upi.length; i++) {
                    System.out.println(upi[i]);
                }
                
                Class.forName("oracle.jdbc.driver.OracleDriver");// 加载Oracle驱动程序
                System.out.println("开始尝试连接数据库!");
                String url = "jdbc:oracle:" + "thin:@"+ upi[2];  //10.232.132.6:1521:p2b";
                String user = upi[0];// 用户名,系统默认的账户名
                String password = upi[1];// 你安装时选设置的密码
                con = DriverManager.getConnection(url, user, password);// 获取连接
                System.out.println("连接成功!");
                System.out.println("con前:" + con);
    
                return con;
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e.getMessage(), "message",
                        JOptionPane.ERROR_MESSAGE);
                return null;
            }
        }
    
    • 获取索引;
    /*
         * 获取主键字段
         */
        public static ArrayList<String> getKeyWord(String tableName)
                throws SQLException {
            try {
                ResultSet rs = null;
                
                con = oracle();
                if(con == null){  //防止oracle链接报错时,连续提示两次错误框;
                    return null;
                }
                
                DatabaseMetaData dbMeta = con.getMetaData();
                
    
                rs = dbMeta.getPrimaryKeys(null, null, tableName.toUpperCase());
    
                ArrayList<String> keyWord = new ArrayList<String>();
                while (rs.next()) {
                    keyWord.add(rs.getObject(4).toString());
                }
                System.out.println("主键: " + keyWord);
    
                if (rs != null)
                    rs.close();
                if (con != null)
                    con.close();
                System.out.println("数据库连接已关闭!");
                System.out.println("con后(主键):" + con);
                return keyWord;
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e.getMessage(), "message",
                        JOptionPane.ERROR_MESSAGE);
                return null;
            }
    
        }
    
    • 交易前查询按钮主要动作是把数据库表的记录临时存放到List<Map<String, String>>,后续再跟交易后查询的记录做比对。
    /*
         * 获取交易前数据
         */
        public static List<Map<String, String>> getTradeBef(String tableName,
                String queryConditon) throws SQLException {
            try {
                ResultSet result = null;// 创建一个结果集对象
                PreparedStatement pre = null;// 创建预编译语句对象,一般都是用这个而不用Statement
                String sql = "";
    
                List<Map<String, String>> tradeBef = new ArrayList<Map<String, String>>();
                ArrayList<String> tableHead = new ArrayList<String>();
    
                tableHead = getTableHead(tableName);
                if(tableHead == null){  //防止oracle链接报错时,连续提示两次错误框;
                    return null;
                }
                
                if (!queryConditon.equals(""))
                    sql = "select * from " + tableName + " where " + queryConditon;
                else
                    sql = "select * from " + tableName;
    
                con = oracle();
                if(con == null){  //防止oracle链接报错时,连续提示两次错误框;
                    return null;
                }
                
                pre = con.prepareStatement(sql);// 实例化预编译语句
                result = pre.executeQuery();
    
                while (result.next()) {
                    Map<String, String> map = new HashMap<String, String>();
                    for (int i = 0; i < tableHead.size(); i++) {
                        map.put(tableHead.get(i),
                                result.getString(tableHead.get(i)));
                    }
    
                    tradeBef.add(map); // 交易前
                }
                System.out.println("交易前map: " + tradeBef);
                /*
                 * System.out.println("交易前第一个map的商户名: " +
                 * tradeBef.get(0).get("MERCHANT_NAME"));
                 */
    
                if (result != null)
                    result.close();
                if (pre != null)
                    pre.close();
                if (con != null)
                    con.close();
                System.out.println("数据库连接已关闭!");
                System.out.println("con后(交易前):" + con);
    
                JOptionPane.showMessageDialog(null, "交易前查询成功", "message", 1); // 提示交易前查询成功
    
                return tradeBef;
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e.getMessage(), "message",
                        JOptionPane.ERROR_MESSAGE);
                return null;
            }
    
        }
    
    • 交易后查询按钮的主要动作是把数据库的记录跟交易前获取list<map>做对比,然后写入excel结果文件,对前后不一致的字段标注相应的颜色。
        /*
         * 获取交易后数据
         */
        public static List<Map<String, String>> getTradeAft(String tableName,
                String queryConditon) throws SQLException {
            try {
                ResultSet result = null;// 创建一个结果集对象
                PreparedStatement pre = null;// 创建预编译语句对象,一般都是用这个而不用Statement
                String sql = "";
    
                List<Map<String, String>> tradeAft = new ArrayList<Map<String, String>>();
                ArrayList<String> tableHead = new ArrayList<String>();
    
                tableHead = getTableHead(tableName);
                if(tableHead == null){  //防止oracle链接报错时,连续提示两次错误框;
                    return null;
                }
    
                if (!queryConditon.equals(""))
                    sql = "select * from " + tableName + " where " + queryConditon;
                else
                    sql = "select * from " + tableName;
    
                con = oracle();
                if(con == null){  //防止oracle链接报错时,连续提示两次错误框;
                    return null;
                }
                
                pre = con.prepareStatement(sql);// 实例化预编译语句
                result = pre.executeQuery();
    
                while (result.next()) {
                    Map<String, String> map = new HashMap<String, String>();
                    for (int i = 0; i < tableHead.size(); i++) {
                        map.put(tableHead.get(i),
                                result.getString(tableHead.get(i)));
                    }
    
                    tradeAft.add(map); // 交易前
                }
                System.out.println("交易后map: " + tradeAft);
                /*
                 * System.out.println("交易后第一个map的商户名: " +
                 * tradeAft.get(0).get("MERCHANT_NAME"));
                 */
    
                if (result != null)
                    result.close();
                if (pre != null)
                    pre.close();
                if (con != null)
                    con.close();
                System.out.println("数据库连接已关闭!");
                System.out.println("con后(交易后):" + con);
    
                return tradeAft;
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(null, e.getMessage(), "message",
                        JOptionPane.ERROR_MESSAGE);
                return null;
            }
    
        }
    
    /*
         * 交易前后数据对比
         */
        public static String compare(List<Map<String, String>> tradeBef,
                List<Map<String, String>> tradeAft, String tableName)
                throws SQLException, WriteException, IOException, BiffException {
    
            String keyValue1 = "";
            String keyValue2 = "";
            String keyValue3 = "";
            String keyValue4 = "";
            ArrayList<String> tableHead = new ArrayList<String>();
            tableHead = getTableHead(tableName);
            if(tableHead == null){  //防止oracle链接报错时,连续提示两次错误框;
                return "";
            }
    
            String filePath = cOutputFile(tableHead); // 创建文件
    
            ArrayList<String> list1 = new ArrayList<String>(); // 临时存储交易前的记录
            ArrayList<String> list2 = new ArrayList<String>(); // 临时存储交易后的记录
            /****************************************************************************/
            /*
             * 1、处理tradeBef存在但tradeAft不存在的记录; 2、处理tradeBef和tradeAft都存在的记录;
             */
            for (int i = 0; i < tradeBef.size(); i++) {
                keyValue1 = "";
                for (int a = 0; a < key.size(); a++) { // 获取交易前记录主键的值
                    keyValue1 += tradeBef.get(i).get(key.get(a));
                }
                System.out.println("keyValue1: " + keyValue1);
    
                for (int k = 0; k < tableHead.size(); k++) {
                    list1.add(tradeBef.get(i).get(tableHead.get(k))); // 临时存储交易前的记录
                }
    
                for (int j = 0; j < tradeAft.size(); j++) { // 遍历交易后的记录
                    keyValue2 = "";
                    for (int b = 0; b < key.size(); b++) { // 获取交易后记录主键的值
                        keyValue2 += tradeAft.get(j).get(key.get(b));
                    }
                    System.out.println("keyValue2: " + keyValue2);
    
                    if (keyValue1.equals(keyValue2)) { // 记录在tradeBef和tradeAft都存在
                        for (int k = 0; k < tableHead.size(); k++) {
                            list2.add(tradeAft.get(j).get(tableHead.get(k))); // 临时存储交易后的记录
                        }
                        break;
                    }
                }
    
                if (list2.size() == 0) { // tradeBef存在,tradeAft不存在
                    wOutputFile(filePath, list1, null, tableHead); // 写结果文件
                } else {
                    wOutputFile(filePath, list1, list2, tableHead);
                }
                System.out.println("交易前list1: " + list1);
                System.out.println("交易后list2: " + list2);
                list1.clear(); // 清除临时记录
                list2.clear();
            }
    
            /****************************************************************************/
            /*
             * 1、处理tradeBef不存在但tradeAft存在的记录;
             */
            for (int i = 0; i < tradeAft.size(); i++) {
                keyValue3 = "";
                for (int a = 0; a < key.size(); a++) { // 获取交易后记录主键的值
                    keyValue3 += tradeAft.get(i).get(key.get(a));
                }
    
                for (int k = 0; k < tableHead.size(); k++) {
                    list2.add(tradeAft.get(i).get(tableHead.get(k))); // 临时存储交易后的记录
                }
    
                for (int j = 0; j < tradeBef.size(); j++) { // 遍历交易前的记录
                    keyValue4 = "";
                    for (int b = 0; b < key.size(); b++) { // 获取交易前记录主键的值
                        keyValue4 += tradeBef.get(j).get(key.get(b));
                    }
    
                    if (keyValue3.equals(keyValue4)) {
                        list2.clear(); // 记录在tradeBef和tradeAft都存在,则清空list
                        break; // 跳出循环
                    }
                }
                if (list2.size() != 0) { // 交易后记录list非空
                    wOutputFile(filePath, null, list2, tableHead);
                    System.out.println("tradeBef不存在但tradeAft存在 list2: " + list2);
                }
                list2.clear();
            }
            return filePath;
    
        }
    
        /*
         * cOutputFile方法创建对比结果文件,入参为表头list;
         */
        public static String cOutputFile(ArrayList<String> list)
                throws IOException, WriteException {
    
            String temp_str = "";
            Date dt = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            temp_str = sdf.format(dt); // 获取时间戳
    
            // 相对路径默认为 D:\Progrom Files\apache-jmeter-3.1\bin "D:\\\\" +
            String filepath = "result\\" + "比对结果" + "_output_" + "_" + temp_str
                    + ".xls"; // 以时间戳命名结果文件,确保唯一
    
            File output = new File(filepath);
    
            if (!output.isFile()) {
                output.createNewFile(); // 如果指定文件不存在,则新建该文件
                WritableWorkbook writeBook = Workbook.createWorkbook(output);
                WritableSheet Sheet = writeBook.createSheet("比对结果", 0); // createSheet(sheet名称,第几个sheet)
    
                for (int i = 0; i < list.size(); i++) {
                    // CellView cellView = new CellView();
                    // cellView.setAutosize(true); //设置自动大小
                    // Sheet.setColumnView(i, cellView);//根据内容自动设置列宽
    
                    Sheet.setColumnView(i, 25); // 设置列宽度setColumnView(列号,宽度)
                    WritableFont headfont = new WritableFont(
                            WritableFont.createFont("宋体"), 11, WritableFont.BOLD); // 字体样式
                    WritableCellFormat headwcf = new WritableCellFormat(headfont);
                    headwcf.setBackground(Colour.GRAY_25); // 灰色颜色
                    headwcf.setAlignment(Alignment.CENTRE); // 设置文字居中对齐方式;
                    headwcf.setVerticalAlignment(VerticalAlignment.CENTRE); // 设置垂直居中;
    
                    Label labe00 = new Label(i, 0, list.get(i), headwcf); // Label(列号,行号,内容)
                    Sheet.addCell(labe00);
                }
    
                writeBook.write();
                writeBook.close();
            }
            return filepath;
        }
    
        /*
         * wOutputFile方法写对比结果文件,入参为 文件路径、交易前记录list、交易后记录list、表头list;
         */
        public static void wOutputFile(String filepath, ArrayList<String> list1,
                ArrayList<String> list2, ArrayList<String> tableHead)
                throws IOException, RowsExceededException, WriteException,
                BiffException {
    
            File output = new File(filepath);
            InputStream instream = new FileInputStream(filepath);
            Workbook readwb = Workbook.getWorkbook(instream);
            WritableWorkbook wbook = Workbook.createWorkbook(output, readwb); // 根据文件创建一个操作对象
    
            WritableSheet readsheet = wbook.getSheet(0);
            int rsRows = readsheet.getRows(); // 获取Sheet表中所包含的总行数
    
            WritableFont font = new WritableFont(WritableFont.createFont("宋体"), 10,
                    WritableFont.NO_BOLD);// 字体样式
    
            Cell cell1 = readsheet.getCell(0, rsRows);
            if (cell1.getContents().equals("")) {
                for (int m = 0; m < tableHead.size(); m++) {
    
                    WritableCellFormat wcf = new WritableCellFormat(font); // 字体样式设置
    
                    if (list1 != null && list2 != null) { // 交易前后记录都存在
                        if (list1.get(m) != null && list2.get(m) != null) {// 某些字段可能为null,需加判断
                            if (!list1.get(m).toString()
                                    .equals(list2.get(m).toString())) {
                                wcf.setBackground(Colour.RED); // 不一致字段标注红色
                            }
                        }
                        Label labetest1 = new Label(m, rsRows, list1.get(m), wcf);
                        readsheet.addCell(labetest1);
                        Label labetest2 = new Label(m, rsRows + 1, list2.get(m),
                                wcf);
                        readsheet.addCell(labetest2);
                    }
    
                    if (list1 != null && list2 == null) { // 交易前记录存在,交易后记录不存在
                        wcf.setBackground(Colour.ROSE); // 不一致字段标注红色
                        Label labetest1 = new Label(m, rsRows, list1.get(m), wcf);
                        readsheet.addCell(labetest1);
                    }
                    if (list1 == null & list2 != null) { // 交易前记录不存在,交易后记录存在
                        wcf.setBackground(Colour.RED); // 不一致字段标注红色
                        Label labetest2 = new Label(m, rsRows, list2.get(m), wcf);
                        readsheet.addCell(labetest2);
                    }
                }
            }
            wbook.write();
            wbook.close();
        }
    

      至此,DBCompare小工具开发完成,觉得对工作有帮助的童鞋,赶紧尝试一下吧。

    相关文章

      网友评论

      • cooling2016:工具开源,上传?
        cooling2016:@Tomandy 看比赛
        Tomandy:@cooling2016 自己随便写的一个小工具,方便测试检查表记录😂

      本文标题:DBCompare小工具研发

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