Jmeter测试及应用--使用Java请求进行Dubbo接口的测试

如何构建一个Dubbo接口测试的通用框架

从上面的流程我们可以看出,测试类大致的一个结构:

  • 使用json文件来构造测试数据
  • java程序只对json文件进行解析
  • 接口调用成功后,用json文件中的期望数据来对接口返回数据进行比对,判断调用是否成功

json文件的定义

{
  "Connection": {
    "URL": "101.219.255.73:50883",
    "SERVICE_NAME": "com.company.mdapi.sdk.material.export.MaterialApiService",
    "VERSION": "1.0.0",
    "METHOD": "queryUnboundListByPage",
    "HELPCLASS": "com.utils.common.helper.MaterialApiService.QueryUnboundListByPageHelper"
  },
  "Random": false,
  "Args": {
    "sourceSystem": 2,
    "querySourceSystem": null,
    "materialCode": "MD_S6006",
    "materialName": null,
    "materialType": null,
    "pkId": null,
    "shipperCode": "ZA01",
    "storageCenterCode": "HZA1",
    "pager": {
      "page": 1,
      "rows": 5,
      "totalCount": null,
      "pageOffset": null,
      "sort": "ID",
      "order": "ASC",
      "totalPage": null,
      "pageCode": 7,
      "startPageIndex": null,
      "endPageIndex": null,
      "previewPage": null,
      "nextPage": null
    }
  },
  "Verify": false
}

参数具体定义:

  • Connection:Dubbo服务的地址URL、服务名称SERVICE_NAME、版本号VERSION、远程接口调用的方法METHOD、
    数据转化处理的辅助类HELPCLASS。
  • Random:用来是能随机数设置,压力测试类似Add数据库操作时可以绕过数据库预设好的唯一性校验。
  • Args:调用接口时,传入的参数,这里提供的参数需要在辅助类中转换成接口参数,然后调用接口。
  • Verify:保留值,暂无使用

Java程序实现数据转换及接口调用

  • 辅助的Help类,需要继承SampleHelper类,同时实现其中的两个抽象方法readJsonFile和callRemoteMethod,
    分别用来读取json配置文件和调用远程方法(实际测试人员只需要实现这两个方法就可以进行Dubbo接口测试)。
public class AddMaterialListHelper extends SampleHelper<Result<List<FailData>>> {

    public static final String[] RANDOM_FIELD = {"materialCode","materialName"};
    
    @Override
    public Map<String, Object> readJsonFile(String jsonPath) {
        JsonParser parser = new JsonParser();

        try {
            JsonObject json=(JsonObject) parser.parse(new FileReader(jsonPath));
            Map<String, Object> values = new HashMap<String, Object>();
            UtilsHelper.getInstance().getConnectionArgument(values, json);

            JsonObject args=json.get("Args").getAsJsonObject();
            if (!args.get("data").isJsonNull()) {
                String jsonArray = args.get("data").getAsJsonArray().toString();
                //TODO
                Gson gson = new Gson();
                @SuppressWarnings("serial")
				List<MaterialInterfaceDTO> dtoList = gson.fromJson(jsonArray,
                        new TypeToken<List<MaterialInterfaceDTO>>() {
                        }.getType());
                RandomNum.setRandom(json , RANDOM_FIELD , dtoList);
                values.put("data", dtoList);
            }

            if (!args.get("sourceSystem").isJsonNull()) {
                values.put("sourceSystem", new Integer(args.get("sourceSystem").getAsInt()));
            }

            return values;

        } catch (JsonIOException e) {
            e.printStackTrace();
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Result<List<FailData>> callRemoteMethod(Object object, Map<String, Object> values) {
    	 MaterialInterfaceService service = (MaterialInterfaceService) object;
         @SuppressWarnings("unchecked")
		Result<List<FailData>> callResult = service.addMaterialList (
        		 (int) values.get("sourceSystem"),
                 (List<MaterialInterfaceDTO>) values.get("data"));
         return callResult;
    }
}
  • 这里有个注意点,由于个博主所在的团队把接口参数封装成了一个可序列化的class类,所以需要进行数据转化,有些公司的
    接口参数直接传json字符串,那么只需要把json转换为字符串进行传参就可以。

    参数封装为序列化的class类:
    public class MaterialInterfaceDTO implements Serializable {
        private static final long serialVersionUID = -3725469669741557392L;
        private String materialCode;
        private String materialName;
        private Integer materialType;
        private Integer importFlag;
        private String sixNineCode;
        private Long expirationDate;
        private Long packingSpecification;
        private String basicUnit;
        private String minSaleUnit;
        private String basicUnitName;
        private String minSaleUnitName;
        private String materialImageUrl;
        private Integer transportFlag;
        private Integer sourceSystem;
        private String createName;
        private String updaterName;
    
        public MaterialInterfaceDTO() {
        }
    
        public String getMaterialCode() {
            return this.materialCode;
        }
    
        public void setMaterialCode(String materialCode) {
            this.materialCode = materialCode;
        }
    
        public String getMaterialName() {
            return this.materialName;
        }
    
        public void setMaterialName(String materialName) {
            this.materialName = materialName;
        }
    
        public Integer getMaterialType() {
            return this.materialType;
        }

     

  • 在init中通过java反射机制,获取json配置文件中设置好的辅助类的对象,然后在runTest中调用对应辅助类中
    callRemoteMethod,返回的结果解析后放到SampleResult的responeData,用来在jmeter中使用后置处理器进行
    结果判断。
    package com.utils.common;
    
    import com.alibaba.dubbo.config.ApplicationConfig;
    import com.alibaba.dubbo.config.ReferenceConfig;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import org.apache.jmeter.config.Arguments;
    import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
    import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
    import org.apache.jmeter.samplers.SampleResult;
    
    import java.util.Map;
    
    public class RunMethodTest extends AbstractJavaSamplerClient {
        private static String JMX_PATH = null;
        private static String TAG = Thread.currentThread().getStackTrace()[1].getClassName();
        private SampleHelper helper = null;
        private Map<String, Object> values = null;
        private Map<String, Object> config = UtilsHelper.getInstance().getConfigProperties();
        private String ARGS_FILE;
        private Object object;
    
        public void setupTest(){
            //定义测试初始值,setupTest只在测试开始前使用
            System.out.println("setupTest");
        }
    
        public void init() {
            // 当前应用配置
            ApplicationConfig application = new ApplicationConfig();
            application.setName(TAG);
    
            // 获取具体参数配置路径
            if ("true".equals(config.get("DEBUG").toString())) {
                JMX_PATH = ARGS_FILE;
            } else {
                JMX_PATH = UtilsHelper.getInstance().getScriptPath(config.get("SCRIPT_HOME").toString(), ARGS_FILE);
            }
            Map<String, Object> helpArgs = UtilsHelper.getInstance().getHelpClassAndMethod(JMX_PATH);
            helper = (SampleHelper)UtilsHelper.getInstance().invokeStaticMethodByReflect(
                    (String) helpArgs.get("HELPCLASS"),
                    (String) helpArgs.get("HELPMETHOD")
            ) ;
    
            values = helper.readJsonFile(JMX_PATH);
    
            // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
            // 引用远程服务,配置dubbo服务版本、服务名称、url地址
            ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
            reference.setApplication(application);
            reference.setTimeout(20000);
            reference.setVersion(values.get("conn_version").toString());
            reference.setInterface(values.get("conn_service_name").toString());
            reference.setUrl(values.get("conn_url").toString());
    
            // 和本地bean一样使用xxxService
            object = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用\
        }
    
        public SampleResult runTest(JavaSamplerContext arg0) {
            SampleResult sr = new SampleResult(); ;
            try {
                //获取参数
                ARGS_FILE = arg0.getParameter("ARGS_FILE");
    
                //dubbo初始化
                init();
    
                //jmeter结果对象
    //            sr.setSampleLabel(TAG);
                sr.sampleStart();
                sr.setSuccessful(true);
    
                String res = helper.handleResult(helper.callRemoteMethod(object, values));
    
                sr.sampleEnd(); // jmeter 结束统计响应时间标记
                if (res != null) {
                    JsonObject response = new JsonParser().parse(res).getAsJsonObject();
                    System.out.println("\n*************测试返回值****************\n");
                    System.out.print(response.toString()+"\n");
                    if (response.get("code").getAsInt() != 0) {
                        sr.setSuccessful(false);
                    }
                    sr.setResponseData(response.toString(), "UTF-8");
    //                if (null != response.get("data")) {
    //                    sr.setResponseData(response.get("data").toString(), "UTF-8");
    //                    System.out.print(response.get("data").toString()+"\n");
    //                } else if (null != response.get("result")) {
    //                    sr.setResponseData( response.get("result").toString(), "UTF-8");
    //                }
                } else {
                    System.out.print("handleResult return null\n");
                }
    
    
            } catch (Exception e) {
                e.printStackTrace();
                sr.setResponseCode("999");
                sr.setResponseMessage(e.getMessage());
                sr.setSuccessful(false);
            }
            return sr;
        }
    
        public Arguments getDefaultParameters(){
            //参数定义,显示在前台,也可以不定义
            Arguments params = new Arguments();
            params.addArgument("ARGS_FILE", "");
            return params;
        }
    
        public void teardownTest(JavaSamplerContext arg0){
            super.teardownTest(arg0);
        }
    
    }
    

 

Doe 发布 [V1.0.0] 前段时间排查某问题的时候,想要快速知道某些dubbo接口(三无)的响应结果,但不想启动项目(因为这些项目不是你负责的,不会部署而且超级笨重),也不想新建一个dubbo客户端项目(占地方),也不想开telnet客户端连接口(麻烦而且有限制)。所以扣了dubbo的netty模块源码,封装了个收发客户端集成一个工具,可以快速调试dubbo接口。源码地址:https://github.com/VIPJoey/doe 极简模式 普通模式 目录结构 mmc-dubbo-api 接口项目,主要用于测试。 mmc-dubbo-provider dubbo提供者项目,主要用于测试。 mmc-dubbo-doe 主项目,实现dubbo接口调试。 deploy 部署文档 功能特性 极简模式:通过dubbo提供的telnet协议收发数据。 普通模式:通过封装netty客户端收发数据。 用例模式:通过缓存数据,方便下一次操作,依赖普通模式。 增加依赖:通过调用maven命令,下载jar包和热加载到系统,主要用来分析接口方法参数,主要作用在普通模式。 依赖列表:通过分析pom文件,展示已经加载的jar包。 其它特性 springboot 整合 redis,支持spring el 表达式。 springboot 整合 thymeleaf。 springboot 整合 logback。 netty rpc 实现原理。 开发环境 jdk 1.8 maven 3.5.3 dubbo 2.6.1 lombok 1.16.20 idea 2018 windows 7 安装步骤 安装jdk 安装maven,并设置好环境变量,仓库目录。 进入mmc-dubbo-api目录,执行mvn clean install命令,省api的jar包。 进入mmc-dubbo-doe目录,执行mvn clean install 命令,在target目录生成dubbo-doe-1.0.0-RELEASE.jar 在F盘(可以任意盘)创建目录F:\app\doe 把dubbo-doe-1.0.0-RELEASE.jar拷贝到F:\app\doe 把deploy目录中的所有文件拷贝到F:\app\doe 如果您电脑安装了git bash,可以在bash窗口运行 ./deploy.sh start,否则如果没有安装git bash,只能打开cmd切换到F:\app\doe目录,然后执行java -jar dubbo-doe-1.0.0-RELEASE.jar --spring.profiles.active=prd 打开浏览器,访问地址:http://localhost:9876/doe/home/index 全剧终
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值