IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 接口测试工具设计与实现 -> 正文阅读

[开发测试]接口测试工具设计与实现

对于接口测试的方法,我们有多种选择,譬如:使用jmeter工具中的http请求,postman请求,和偏向代码层面的自动化接口测试框架。在分别使用这三者方法进行接口测试后,发现各有所优缺。

1、 postman比较适合单个接口测试请求,对于复杂的业务使用其进行自动化接口测试用例设计时比较繁琐。
2、 jmeter工具对于业务测试比较友好,可以通过前置条件和后置处理进行测试数据的构造,然后进行自动化接口测试用例的设计并执行,对于接口的测试结果输出比较直观。但是对于单个接口测试需要设计多个测试用例和测试数据,在后期的维护过程中不是很方便。
3、 自动化接口测试框架使用更偏向于单元测试层面,需要了解和懂得Java语言,对于测试结果的处理不是很友好,通过断言进行判断。在测试用例设计的过程中更全面一些,但测试结果没有jmeter工具那么直观。同时维护起来比较麻烦。

综上,在测试性能过程中了解了jmeter工具中的Java请求,如是尝试通过jmeter+Java+HttpclientUtil的使用进行接口测试。

难点:

  1. 对于不同的系统接口比较多,所以需要针对每个接口设计一个类,并且类中需要继承JavaSampleClient类,类中需要包含getDefaultParameters(设置入参),setupTest(初始化方法),runTest(测试主体),teardownTest(测试结束)。每个类中含有大量重复数据并且每个方法的具体实现不同。因此,编写出的java请求比较冗余和且维护成本比较大。
  2. 测试响应结果的校验和断言需要针对每个测试用例进行设计,如果设计在代码里面维护比较麻烦而且场景覆盖比较低。如果借用jmeter工具的断言进行校验需要编写大量的BeanShell脚本。而且需要将接口响应结果直接打印。
  3. 接口参数每次改动都需要修改java请求的源码然后重新生成jar包增加了测试的工作量。相对于纯使用jmeter工具而言更复杂了。

针对以上的难点,研究了开发提供的单元测试后,针对上述问题进行了设计和解决。最终通过如下方法进行重新设计。

  • 重写一个类OverWriteJavaSampleClient继承JavaSampleClient类,并将JavaSampleClient类中的方法重定义overGettDefaultParameters、overSetupTest、overRun、overRunTest方法,然后再其中实现JavaSampleClient的具体方法;对于接口中的参数定义成一个实体类,包括code(编号)、title(接口名称)、url(请求路径)、requestType(请求类型)、paramType(参数类型)、headerMsg(消息头参数)、paramsMag(接口参数)、assertMsg(断言)、description(接口描述)。每个接口名称对应一个实体类,且接口的参数通过map键值对存储在list中。接口参数数据通过Excel读取获取后存储为对应的格式。在方法中通过实体类中的参数判断接口类型,参数类型进行HttpClientUtil工具类调用发送http请求。
  • 由于每个接口响应数据格式比较统一,只在代码中通过判断校验部分数据,具体的响应data里面的内容公共Jmeter工具进行校验。对于响应数据进行重新定义输出。
  • 每个接口需要对于一个类,但是类里面的实现只需要通过Excel表中的title来进行参数回去。因此,类中的实现表简单,基本是统一的,减少了代码的冗余,同时参数可通过Excel进行维护。

针对上述设计思路,并开始了设计实现。包括两个部分,Excel的定义和java脚本的实现。

Excel的定义
字段	| 意义	约束	补充
code	编号	自增,唯一性	
title	接口名	唯一性,作为主键使用	
url	请求url	无	
requestType	请求类型	1-	get请求
2-	post请求	后续可继续补充,目前只涉及这几种
paramType	参数类型	1-	param参数类型
2-	json参数类型
3-	自定义参数类型	
headerMsg	请求消息头参数	消息头,可为空。一般包含token和cookie,多个时使用英文“,”进行分隔	
paramsMsg	请求消息体参数	请求参数,多个时使用英文“,”进行分隔	
assertMsg	断言参数	断言参数,多个时使用英文“,”进行分隔	目前只做了“code-message”、“total-value”、和不校验三种
description	接口描述

代码实现:
OverWriteJavaSampleClient类实现方法

public abstract class OverWriteJavaSampleClient extends AbstractJavaSamplerClient {
    Map<String,RemoteServerInfoEntity> setRemoteServerInfo;
    {
        try {
            setRemoteServerInfo = setRemoteServerInfo();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //自定义java请求方法入参,设置可用参数及默认值
    public Arguments overGettDefaultParameters(String key){
        Arguments params = new Arguments();
        params.addArgument("httpHost","");
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getHeaderMsg().entrySet()) {
            params.addArgument(stringStringEntry.getKey(),"");
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getParameterMsg().entrySet()) {
            params.addArgument(stringStringEntry.getKey(),"");
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getAssertMsg().entrySet()) {
            params.addArgument(stringStringEntry.getKey(),"");
        }
        return params;
    }

    public void overSetupTest(JavaSamplerContext arg0,String key) {
        String httpHost = arg0.getParameter("httpHost");
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getHeaderMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getParameterMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getAssertMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }
    }

    public String overRun(String httpHost, String key) {
        String respJson = "";
        StringBuilder urlBuff = new StringBuilder();
        urlBuff.append(httpHost).append(setRemoteServerInfo.get(key).getUrl());
        if(!setRemoteServerInfo.get(key).getHeaderMsg().isEmpty()) {
            if (setRemoteServerInfo.get(key).getRequestType() == 1) {
                respJson = HttpClientUtils.doGetRequest(urlBuff.toString(), setRemoteServerInfo.get(key).getHeaderMsg(), setRemoteServerInfo.get(key).getParameterMsg());
            } else {
                if (setRemoteServerInfo.get(key).getParamType() == 1) {
                    respJson = HttpClientUtils.doPostRequest(urlBuff.toString(), setRemoteServerInfo.get(key).getHeaderMsg(), setRemoteServerInfo.get(key).getParameterMsg(), null);
                } else {
                    StringEntity entity = map2StringEntity((HashMap<String, String>) setRemoteServerInfo.get(key).getParameterMsg());
                    respJson = HttpClientUtils.doPostRequest(urlBuff.toString(), setRemoteServerInfo.get(key).getHeaderMsg(), null, entity);
                }
            }
        }
        else{
            if (setRemoteServerInfo.get(key).getRequestType() == 1) {
                respJson = HttpClientUtils.doGetRequest(urlBuff.toString(), null, setRemoteServerInfo.get(key).getParameterMsg());
            } else {
                if (setRemoteServerInfo.get(key).getParamType() == 1) {
                    respJson = HttpClientUtils.doPostRequestwithCookie(urlBuff.toString(), null, setRemoteServerInfo.get(key).getParameterMsg(), null);
                } else {
                    StringEntity entity = map2StringEntity((HashMap<String, String>) setRemoteServerInfo.get(key).getParameterMsg());
                    respJson = HttpClientUtils.doPostRequestwithCookie(urlBuff.toString(), null, null, entity);
                }
            }
        }
        return respJson;
    }

    public SampleResult overRunTest(JavaSamplerContext arg0, String key){
        String httpHost = arg0.getParameter("httpHost");
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getHeaderMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getParameterMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getAssertMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
        }

        //定义请求和响应相关信息,输出至生成结果树
        //生成结果树中请求消息和响应消息内容
        String title = " "+"\n"+"\t"+
                "                                   接口:"+setRemoteServerInfo.get(key).getDescription()+"                                  "+"\n"+"\t"+
                " "+"\n";
        String httpUrl = "HttpUrl:" + httpHost + setRemoteServerInfo.get(key).getUrl()+"\n";
        String requestBody = "";
        String assertMsg = "断言字段期望值:";
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getParameterMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
            requestBody += "\n"+"\t"+"\""+ stringStringEntry.getKey()+"\""+":" + stringStringEntry.getValue() + ",     ";
        }
        for (Map.Entry<String, String> stringStringEntry : setRemoteServerInfo.get(key).getAssertMsg().entrySet()) {
            stringStringEntry.setValue(arg0.getParameter(stringStringEntry.getKey()));
            assertMsg += "\""+ stringStringEntry.getKey()+"\""+":" + stringStringEntry.getValue() + ",     ";
        }
        String requestJson = "RequestJson:"+"{" +requestBody+"\n" + "}"+"\n"+assertMsg;
        Map<String, String>  assertResult =new HashMap<>();

        SampleResult sr = new SampleResult();
        String request_msg = "";
        request_msg = request_msg + title+httpUrl + requestJson ;//+ assertMsg;
        String response_msg = "";
        response_msg = response_msg+title;

        try {
            sr.sampleStart();
            String runMap = this.overRun(httpHost,key);
            if(setRemoteServerInfo.get(key).getAssertMsg().containsKey("exp_code")){
                assertResult = AssertDeal.AssertDealofCodeMessage(runMap,setRemoteServerInfo.get(key).getAssertMsg());
                response_msg += assertResult.get("assertResult") ;
                sr.setSuccessful(Boolean.parseBoolean(assertResult.get("Bool")));
            }
            else if(setRemoteServerInfo.get(key).getAssertMsg().containsKey("exp_total")){
                assertResult = AssertDeal.AssertDealofTotalResult(runMap,setRemoteServerInfo.get(key).getAssertMsg());
                response_msg += assertResult.get("assertResult") ;
                sr.setSuccessful(Boolean.parseBoolean(assertResult.get("Bool")));
            }
            else {
                if(!runMap.equals(null)) {
                    response_msg += runMap;
                    sr.setSuccessful(Boolean.parseBoolean(assertResult.get(true)));
                }
                else {
                    response_msg += runMap;
                    sr.setSuccessful(false);
                }
            }

        }catch (Throwable e){
            sr.setSuccessful(false);
            e.printStackTrace();
        }finally {
            sr.sampleEnd();
        }

        System.out.println(request_msg);
        sr.setRequestHeaders(request_msg);
        sr.setResponseData(response_msg,"utf-8");
        System.out.println(response_msg);
        return sr;
    }

    // 结束方法,实际运行时每个线程仅执行一次,在测试方法运行结束后执行
    public void overTeardownTest(JavaSamplerContext arg0) {
    }

    public Map<String,RemoteServerInfoEntity> setRemoteServerInfo() throws Exception {
        List<Map<String, String>> line = (List<Map<String, String>>) getLine("E:\\JmeterTest\\file\\interfaceParam.xls");
        int lineSize = line.size();
        Map<String,RemoteServerInfoEntity> paramsSet = new HashMap<>();
        try {
            for(int i=0;i<lineSize;i++) {
                Integer getCode = Integer.parseInt(line.get(i).get("code"));
                String getUrl = line.get(i).get("url");
                int getRequestType = Integer.parseInt(line.get(i).get("requestType"));
                int getParamType = Integer.parseInt(line.get(i).get("paramType"));
                String getTitle = line.get(i).get("title");
                Map<String, String> getHeader = string2Map(line.get(i).get("headerMsg"));
                Map<String, String> getParams = string2Map(line.get(i).get("paramsMsg"));
                Map<String, String> getAssert = string2Map(line.get(i).get("assertMsg"));
                String getDescription = line.get(i).get("description");
                RemoteServerInfoEntity param = new RemoteServerInfoEntity();
                param.setCode(getCode);
                param.setUrl(getUrl);
                param.setParamType(getParamType);
                param.setRequestType(getRequestType);
                param.setTitle(getTitle);
                param.setHeaderMsg(getHeader);
                param.setParameterMsg(getParams);
                param.setAssertMsg(getAssert);
                param.setDescription(getDescription);
                paramsSet.put(getTitle, param);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return paramsSet;
    }

}

举个栗子
登录接口java请求脚本

public class Login extends OverWriteJavaSampleClient {
    String key = "login";

    //自定义java请求方法入参,设置可用参数及默认值
    public Arguments getDefaultParameters(){
        Arguments params =overGettDefaultParameters(key);
        return params;
    }

    // 初始化方法,实际运行时每个线程仅执行一次,在测试方法运行前执行
    // 每个线程测试前执行一次,做一些初始化工作;
    public void setupTest(JavaSamplerContext arg0){
        overSetupTest(arg0,key);
    }


    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        SampleResult sr = overRunTest(arg0,key);
        return sr;
    }

    // 结束方法,实际运行时每个线程仅执行一次,在测试方法运行结束后执行
    public void teardownTest(JavaSamplerContext arg0) {
        overTeardownTest(arg0);
    }

代码层执行结果:
在这里插入图片描述

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:20:21  更:2022-04-06 16:20:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 1:27:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码