前言:由于通过jmeter写的接口自动化木有数据导入和统计分析功能,因此做了二次开发,目的是读取每条case获取接口名称和用例名称,通过获取的case执行结果进行计算,得到详细接口的用例通过率存入DB,并解析出每条case的执行结果存入DB。

流程图如下:

由于包含case的详细数据和接口的统计数据,因此目前暂定2张表。

具体表结构如下:

接口统计表:

用例执行结果详细表:

首先就是如何让jmeter生成一定格式的csv文件。那么问题一:如何把执行结果生成CSV文件?问题二如何生成一定格式的CSV文件?

解决方案问题一:

在"察看结果树"监听器加入存储路径(在文件名写入 路径+文件名):如:

执行jmx文件后会生成一个excResult.csv文件。如:

解决方案步骤二:

满足一定格式就是满足如下格式:

那么如何满足此格式呢?

在jmeter的"察看结果树"监听器Configure配置下取消掉"Save As XML"

好了,到此初步的要求已经达到。

剩下的就是开发脚本,如何读取csv文件并插入DB

代码部分就不上传了,有兴趣的同学可以私聊

上传下如何插入DB吧、数据统计吧

数据统计代码如下:

 public static int getSucNum(String path) throws Exception{
             CsvUtil util = new CsvUtil(path);
             int rowNum = util.getRowNum();
             int caseNum = rowNum -1;
             int sucNum = 0;
             List list = new ArrayList();
             for(int i=1;i<rowNum;i++){
                 String caseName = util.getString(i, 2);
                 String result = util.getString(i, 7);
                 list.add(caseName);
                list.add(result);
                 if(result.equals("true")==true){
                     sucNum +=1;
                       
                 }
                   
             }
            return sucNum ;
        }
 //计算百分比
        public static  String percent(int sucCaseNum, int allCseNum){
             // 创建一个数值格式化对象  
            NumberFormat numberFormat = NumberFormat.getInstance();
            // 设置精确到小数点后2位  
            numberFormat.setMaximumFractionDigits(2);  
            String result = numberFormat.format((float) sucCaseNum / (float) allCseNum * 100);
            return result; 
        }
       
public static String  getPryKey(String path) throws Exception{
            CsvUtil util = new CsvUtil(path);
            String secTitle = util.getString(1, 2);
//            System.out.println("获取检查的接口名称:"+secTitle);
            String subTitle = secTitle.substring(2, secTitle.length());
//            System.out.println("获取接口名称:"+subTitle);
            return subTitle;
        }
      //获取插入DB的接口执行结果(通过率)
        public static String  getExcRate(String path) throws Exception{
            CsvUtil util = new CsvUtil(path);
            int rowNum = util.getRowNum();
            int caseNum = rowNum -1;
            int sucNum = 0;
            for(int i=1;i<rowNum;i++){
                String caseResult = util.getString(i, 7);
//                System.out.println("用例执行结果为:" + caseResult);
                if(caseResult.equals("true")==true){
                        sucNum +=1;
                  }
            }
            String caseRate = CsvUtil.percent(sucNum, caseNum)+"%";
//            System.out.println("用例通过率为:"+caseRate);
            return caseRate;
        }
        //获取插入DB的secordaryTitle&excResult(用例名称)&(true or false)
        public static void  getSecKey(String path) throws Exception{
            CsvUtil util = new CsvUtil(path);
            int rowNum = util.getRowNum();
            String caseName = null;
            for(int i=1;i<rowNum;i++){
                caseName = util.getString(i, 2);
//                System.out.println("用例名称为:"+caseName);
                String caseResult = util.getString(i, 7);
//                System.out.println("用例执行结果为:" + caseResult);
                
            }
        }

插入DB的代码:

  //插入统计数据
        public static boolean insertTotalDB(String primaryTitle,String excVersion,String excTerminal,String excRate,int caseTotalNum,int caseSucNum){
            try {  
                Class.forName("com.mysql.jdbc.Driver");  
      
                String databaseName = "test";// 已经在MySQL数据库中创建好的数据库。  
                String userName = "mobtest";// MySQL默认的root账户名  
                String password = "tuniu520";// 默认的root账户密码为空  
                String connUrl = "jdbc:mysql://10.10.30.200:3306/";//连接地址
                Connection conn = DriverManager.getConnection(connUrl + databaseName, userName, password);  
                PreparedStatement st = null;
                Statement stmt = conn.createStatement();  
                String sql = "create table if NOT EXISTS AutoTest_TotalInterface(id int NOT NULL auto_increment primary key ,permaryTitle varchar(255) ,excVersion varchar(255),excTerminal varchar(255) NOT  NULL DEFAULT 'App' ,excRate varchar(255) ,caseTotalNum int,caseSucNum int,creatTime timestamp NULL DEFAULT CURRENT_TIMESTAMP )";  
                // 创建数据库中的表,  
                int result = stmt.executeUpdate(sql);  
                if (result != -1) {  
                    sql = "insert into AutoTest_TotalInterface(permaryTitle,excVersion,excTerminal,excRate,caseTotalNum,caseSucNum) values(?,?,?,?,?,?)";
                    st = conn.prepareStatement(sql);
                    st.setString(1, primaryTitle);
                    st.setString(2, excVersion);
                    st.setString(3, excTerminal);
                    st.setString(4, excRate);
                    st.setInt(5, caseTotalNum);
                    st.setInt(6, caseSucNum);
                    st.executeUpdate();
                    sql = "SELECT * FROM AutoTest_TotalInterface";  
                    System.out.println(stmt.executeQuery(sql));
                    ResultSet rs = stmt.executeQuery(sql);
                    System.out.println("id\tprimaryTitle\tsexcVersion\texcTerminal\texcRate\tcaseTotalNum\tcaseSucNum\tcreatTime"); 
                    while (rs.next()) {  
                         System.out.println(rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3) + "\t" + rs.getString(4) + "\t" + rs.getString(5) + "\t" + rs.getString(6) + "\t" + rs.getString(7)+ "\t" + rs.getString(8));  
                    }  
                }  
                conn.close();  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
                return false;
            }
            return true;
       }

有2点说明:读取csv文件乱码问题和读取关闭文件(因为结束后会有备份历史记录,因此必须关闭CSV文件)

乱码问题解决方案不要用FileReader而是InputStreamReader可以指定读取编码

public CsvUtil(String fileName) throws Exception {
                this.fileName = fileName;
                 //FileReader可能会根据不同的环境造成从CSV读取时乱码
                br = new BufferedReader(new FileReader(fileName));
                //解决乱码
                br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"utf-8"));
                String stemp;
                while ((stemp = br.readLine()) != null) {
                        list.add(stemp);
                }
                //关闭csv文件
                 br.close();
        }

 

 代码开发基本完成,就差数据备份了,数据备份的代码如下:

package excFile;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;


public class renFile {
    public static boolean renameFile(String path,String oldname,String newname){ 
        File file=new File(path+oldname);  
        if(file.exists())
        {
        file.renameTo(new File(path+newname));
        return true;
        }
            return false;
    }
    public static String currTime(){
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
        String now = df.format(new Date());// new Date()为获取当前系统时间
        return now;
    }
    public static void main(String[] args) {
        String path = "d:\\";
        String oldname = "excResult.csv";
        String newname = "excResult"+renFile.currTime()+".csv";
        System.out.println("获取当前时间:"+renFile.currTime());
        System.out.println("获取最新的名称:"+renFile.renameFile(path, oldname, newname));
    }
}

恭喜,代码开发基本结束,那么如何被jmeter引用?

把开发的代码export为jar包

如导出jar包名为excDB.jar

由于插入DB要有jdbc依赖包。(mysql-jdbc.jar)

导出后,把2个jar放到jmeter的lib/ext目录下,重启jmeter 即可引用。

如下:在jmeter的beanshell(取样器)工具中写入调用函数脚本即可

import readDB.*;
import excFile.*;

String excVersion = "9.1.2";
String excTerminal = "App";

String path = "D:\\excResult.csv";
String primaryTitle = CsvUtil.getPryKey(path);
log.info("获取接口名称:"+primaryTitle);
String excRate = CsvUtil.getExcRate(path);
log.info("获取单个接口用例通过率:"+excRate);

CsvUtil util = new CsvUtil(path);
int rowNum = util.getRowNum();
//log.info("获取行数:"+rowNum);
int caseTotalNum = rowNum -1;
log.info("获取用例总数:"+caseTotalNum);
int caseSucNum = CsvUtil.getSucNum(path);
log.info("获取用例通过数量:"+caseSucNum);
for(int i=1;i<rowNum;i++){
    String secordaryTitle = util.getString(i, 2);
    log.info("获取用例名称:"+secordaryTitle);
    String excResult = util.getString(i, 7);
    log.info("获取用例执行结果:"+excResult);
    //执行insertDB---详细数据
    CsvUtil.insertDetailDB(primaryTitle, secordaryTitle, excVersion, excTerminal, excResult);
}

////执行insertDB---统计数据
CsvUtil.insertTotalDB(primaryTitle, excVersion, excTerminal, excRate, caseTotalNum, caseSucNum);


String dir = "d:\\";
String oldname = "excResult.csv";
log.info("获取最新文件名称:"+renFile.currTime());
String newname = "excResult"+renFile.currTime()+".csv";
log.info("获取最新文件名称:"+newname);
renFile.renameFile(dir, oldname, newname);

大致截图如下:

 

 

导入DB的jmx文件脚本有几个变量强调下:
①excVersion---版本号(如9.1.0)
②excTerminal---终端类型(如App、网站、M站)
③path---csv文件路径(如d:\excResult.csv)
④dir---csv在哪个目录下(如d:\)
⑤oldname---csv文件名(如excResult.csv)


其中import这2个包名要准确,就是你在开发这些class文件时创建的包名

import readDB.*;
import excFile.*;

如:

这样会把存入DB的jmx文件和用例的jmx文件放在一个文件夹下执行,执行循序会根据jmx文件修改时间的正序来执行,因此一定要确保执行case的jmx文件时间要在导入DB的jmx文件前面。
当然也可以把所有按照接口生成的的jmx文件和分别导入DB的jmx文件放在一个文件夹下,但必须渠道入到的CSV文件名不相同,每个对应读取CSV导入DB的jmx文件的指向路径也不同。
基本完成,执行结果就如上面的导入DB的数据一样。

这样整个开发到此结束!!!

还有就是接口名称和用例名称命名规范的问题!

有2个要求:
第一个要求:由于代码做了接口名称获取的规则,是获取第一条接口case名称但不是单纯的获取,是截断了前面2个字符,后面所有字符作为接口名称。
因此要求case输出者在输出接口自动化时第一条case名称命名为“校验XXXX接口”!!这样根据截断规存入DB的接口名称为“XXXX接口”,才符合接口名称命名规范。
第二个要求:jmx文件,一个接口自动化场景输出一个jmx文件,不要在此jmx文件上输出其它的接口case,在这个接口的基础上输出不同场景的case。
否则会把不同接口统计到一个接口中去!

备份的历史记录文件如下:(原文件名+时间戳)。

为什么要renName?

一方面:也是renName的根本原因,因为每次执行的CSV文件,如果在执行接口自动化的jmx文件前不删除,就会把本次的执行结果追加到原csv文件!!!

另一方面:保存历史记录。

最后也就是视图的展现,数据已存入DB,接下来就是读取数据制图即可!

posted on 2017-04-18 18:35  niuzhigang  阅读(622)  评论(0编辑  收藏  举报