侧边栏壁纸
博主头像
一朵云的博客博主等级

拥抱生活,向阳而生。

  • 累计撰写 67 篇文章
  • 累计创建 25 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

接口自动化 -- 基于JMeter的实战攻略(4)

一朵云
2022-05-16 / 0 评论 / 0 点赞 / 1373 阅读 / 9858 字

前言:

  上一篇 接口自动化 -- 基于JMeter的实战攻略(3) 我们已经完成了接口文档读取、执行的操作,现在我们要做的就是输出接口执行结果了。

准备:

1、封装 CSV 工具 jar

基于 openCsv 进行操作,具体可参考其官网:http://opencsv.sourceforge.net/

项目架构:
image.png

①、编写实体类 TestCaseData

package com.xcj.bean;

import com.opencsv.bean.CsvBindByPosition;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestCaseData {

    //接口编号
    @CsvBindByPosition(position = 0)
    private String interfaceNo;

    //接口域名、IP
    @CsvBindByPosition(position = 1)
    private String interfaceIP;

    //接口端口
    @CsvBindByPosition(position = 2)
    private String interfacePort;

    // 接口地址
    @CsvBindByPosition(position = 3)
    private String interfaceAddress;

    //用例编号
    @CsvBindByPosition(position = 4)
    private String caseNo;

    //用例名称
    @CsvBindByPosition(position = 5)
    private String caseName;

    //接口类型
    @CsvBindByPosition(position = 6)
    private String interfaceType;

    //头部参数
    @CsvBindByPosition(position = 7)
    private String headers;

    //测试数据
    @CsvBindByPosition(position = 8)
    private String testData;

    //关联数据,用于接口数据关联传递
    @CsvBindByPosition(position = 9)
    private String associatedData;

    //预期结果
    @CsvBindByPosition(position = 10)
    private String expectedResults;

    //实际结果
    @CsvBindByPosition(position = 11)
    private String actualResults;

    //是否验证sql
    @CsvBindByPosition(position = 12)
    private String ifVerifySql;

    //执行sql
    @CsvBindByPosition(position = 13)
    private String executeSql;

    //预期sql结果
    @CsvBindByPosition(position = 14)
    private String expectedSqlResults;

    //实际sql结果
    @CsvBindByPosition(position = 15)
    private String actualSqlResults;

    //用例状态
    @CsvBindByPosition(position = 16)
    private String caseStatus;

    //执行人
    @CsvBindByPosition(position = 17)
    private String expecteMan;

    //执行时间
    @CsvBindByPosition(position = 18)
    private String executionTime;

    //备注
    @CsvBindByPosition(position = 19)
    private String remarks;

}

②、编写 CSVUtils 工具类

package com.xcj.service;

import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import com.xcj.bean.TestCaseData;
import java.io.*;
import java.util.List;

public class CSVUtils {

    /**
     * 读取csv文件内容成bean实体类
     *
     * @param filePath        csv文件路径
     * @param ignoreFirstLine 忽略首行
     * @param number          读取行数
     * @return
     * @throws FileNotFoundException
     */
    public TestCaseData readCsv(String filePath, boolean ignoreFirstLine, int number) throws FileNotFoundException, UnsupportedEncodingException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
        List<TestCaseData> beans = new CsvToBeanBuilder(bufferedReader).withSkipLines(1)
                .withType(TestCaseData.class).build().parse();
        return beans.get(number);
    }


    /**
     * @param filePath 预写入内容的文件路径
     * @param data     文件内容
     * @throws IOException
     * @throws CsvRequiredFieldEmptyException
     * @throws CsvDataTypeMismatchException
     */
    public void writeCsv(String filePath, TestCaseData data) throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException, IOException {

        try(Writer writer = new FileWriter(filePath, true)){
            StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).build();
            beanToCsv.setOrderedResults(true);

            //判断文件为空时,添加首行
            File file = new File(filePath);
            if (file == null || file.length() == 0 || !file.exists()) {
                beanToCsv.write(new TestCaseData("接口编号", "域名/IP", "端口", "接口地址", "用例编号", "用例名称"
                        , "接口类型", "headers", "测试数据", "关联数据", "预期结果", "实际结果"
                        , "是否验证sql", "执行sql", "预期sql结果", "实际sql结果", "用例状态"
                        , "执行人", "执行时间", "备注"));
            }
            beanToCsv.write(data);
        }
    }
}

③、打包成工具 jar

分享一个我打包好的jar资源:
https://cdn.yiduoyun.space/JMeter%E5%AE%9E%E6%88%98%E7%B3%BB%E5%88%97/ext/csv_tool-1.0-SNAPSHOT-jar-with-dependencies.jar

2、应用 CSV 工具 jar

将 jar 包放入 jmeter 安装目录下的 lib/ext 目录下,重启 jmeter 后生效。

3、BeanShell 监听器(输出文件)

image.png

下面代码中,需要我们写文件的读写文件路径 readFilePath 和 writeFilePath ,具体值可按各自的需求修改。

import com.xcj.bean.TestCaseData;
import com.xcj.service.CSVUtils;
import java.text.SimpleDateFormat;
import java.util.Date;

log.info("最终BeanShell 监听器:后置处理器执行,testCaseStatus的状态为:"+props.get("testCaseStatus"));

if(vars.get("testCaseStatus") == "end"){

//测试模板的路径
String readFilePath = "C:/Users/lx/Desktop/接口测试用例模板.csv";
//输出测试结果的路径
String writeFilePath = "C:/Users/lx/Desktop/接口报告"+ new SimpleDateFormat("yyyyMMdd").format(new Date().getTime()) +".csv";
        
CSVUtils csvUtils = new CSVUtils();
TestCaseData testCaseData = null;
int interfaceNo = Integer.parseInt(vars.get("interfaceNo"));
//log.info("interfaceNo == "+interfaceNo);
log.info("最终BeanShell 监听器:ctx.getThreadNum()=="+ctx.getThreadNum());
try
{
    //自己通过opencsv封装的工具类,readCsv(param1,param2,param3),第一个参数为读取模板的路径,第二个参数为是否忽略第一行,第三个参数为读取行数(0开始)
    testCaseData = csvUtils.readCsv(readFilePath, true, ctx.getThreadNum());
    log.info("最终BeanShell 监听器:"+testCaseData.toString());
    //写入测试结果
    testCaseData.setActualResults(props.get("responseResult"));
    testCaseData.setActualSqlResults(vars.get("dbData"));
    log.info("最终BeanShell 监听器:props.get(flag) : "+ props.get("flag"));
    testCaseData.setCaseStatus(props.get("flag")?"测试通过":"测试未通过");
    testCaseData.setExpecteMan("JMeter 自动化测试");
    String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date().getTime());
    testCaseData.setExecutionTime(format);
    
    try
    {
    	   //自己通过opencsv封装的工具类,writeCsv(param1,param2),第一个参数表示输出文件的路径,第二个表示数据bean实体类
        csvUtils.writeCsv(writeFilePath, testCaseData);
        log.info("最终BeanShell 监听器:写入测试用例成功!");
    }
    catch(CsvDataTypeMismatchException e)
    {
        log.error("最终BeanShell 监听器:CsvDataTypeMismatchException");
        e.printStackTrace();
    }
    catch(CsvRequiredFieldEmptyException e)
    {
        log.error("最终BeanShell 监听器:CsvRequiredFieldEmptyException");
        e.printStackTrace();
    }
    catch(IOException e)
    {
        log.error("最终BeanShell 监听器:IOException");
        e.printStackTrace();
    }
}
catch(FileNotFoundException e)
{
    log.error("最终BeanShell 监听器:FileNotFoundException");
    e.printStackTrace();
}
catch(UnsupportedEncodingException e)
{
    log.error("最终BeanShell 监听器:UnsupportedEncodingException");
    e.printStackTrace();	
}
finally
{
     vars.remove("testCaseStatus");       
}
} 

4、添加聚合报告(可选)

使用 jmeter 可视化工具执行的话,可添加聚合报告来输出 .jtl 文件,方便后续输出 html 测试报告。如若使用指令执行 .jmx 文件,就可以不加这个了,直接在指令中加 -l 文件名.jtl -e -o 生成后的路径 即可。

总结:

  至此,jmeter自动化脚本文件的编写就完成了,下一篇我们将结合 git、maven、jenkins 把这套方案跑起来。

  最后附上完整的 .jmx 文件下载路径:https://cdn.yiduoyun.space/JMeter%E5%AE%9E%E6%88%98%E7%B3%BB%E5%88%97/%E6%A8%A1%E6%9D%BF.jmx

0

评论区