【测试开发】十六、接口测试-接口定义-实现发送接口请求功能

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 【测试开发】十六、接口测试-接口定义-实现发送接口请求功能

基于 springboot+vue 的测试平台开发继续更新。


添加的接口,我要来调试确定是否是通的,那么要发送接口请求,今天来实现这个功能,先预览一下:


1268169-20211106211244374-1265236592.gif


捋一下思路,分为三步走:


  • 点击发送按钮,调用后端接口
  • 后端接口处理内部,发送http接口请求
  • 后端接口把响应返回给前端展示


一、http客户端选型


为了更方便快捷的开发功能,直接选用 hutool 框架中封装好的 http客户端。


官方介绍:Hutool-http 针对JDK 的HttpUrlConnection做一层封装,简化了HTTPS请求、文件上传、Cookie记忆等操作,使Http请求变得无比简单。


Hutool-http的核心集中在两个类:


  • HttpRequest


  • HttpResponse


同时针对大部分情境,封装了HttpUtil工具类。根据Hutool的“便捷性与灵活性并存”原则,HttpUtil 的存在体现了便捷性,那 HttpRequest对象的使用则体现了灵活性,使用此对象可以自定义更多的属性给请求,以适应Http请求中的不同场景(例如自定义header、自定义cookie、自定义代理等等)。


看过介绍,我浏览了下源代码,然后测试了一下,发现可以满足我使用需求。


//    get1
    @Test
    void get1() {
        String result1 = HttpUtil.get("http://localhost:8080/bloomtest/user/useInfo?token=admin-token");
        System.out.println(result1);
    }
    //    get2
    @Test
    void get2() {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", 33);
        String result2 = HttpRequest.get("http://localhost:8080/bloomtest/apiDefinition/getApi")
                    .form(paramMap)
                    .execute()
                    .body();
        System.out.println(result2);
    }


比如,发送get请求,HttpUtil 其实是基于 HttpRequest 的进一步分装,我这里还是直接统一使用 HttpRequest 。


另外,发送 post 请求也很简单,可以直接传入 json 字符串:


@Test
    void testPost() {
        String reqBody = "{\n" +
                "    \"projectName\": \"项目zzz1\",\n" +
                "    \"description\": \"测试新增项目\"\n" +
                "}";
        //链式构建请求
        String result3 = HttpRequest.post("http://localhost:8080/bloomtest/project/add")
//                .header(Header.CONTENT_TYPE, "application/json")//头信息,多个头信息多次调用此方法即可
//                .timeout(20000)//超时,毫秒
                .body(reqBody)
                .execute().body();
    }


关于http请求的常用信息,请求头、参数、delete/put 等等其他方法,框架都是支持的,目前我只实现最基本的需求。


二、后端接口实现


测试过了上面的代码,心里就有数了,在后端接口里就看怎么使用它了。


这个发送请求的接口,目前需要支持如下:


  • get、post 方法
  • 查询参数(/list?id=3)、rest参数(/list/3)以及请求 body(json)

header暂时先不加,目前我项目里的接口都不需要传指定的 header,后期实现了权限之后再对应完善代码。


1. controller 层


ApiDefinitionController 类中继续新增处理器方法。


@PostMapping("/apiTestRun")
  public Result apiTestRun(@RequestBody ApiRunTestRequest apiRunTestRequest) {
      return Result.success(apiDefinitionService.apiTestRun(apiRunTestRequest));
  }


2. service 层


对应service层实现,先放出全部代码,目前还是以初期实现为主,代码后续可能会进一步优化:


public JSONObject apiTestRun(ApiRunTestRequest request) {
      // url 拼接
      String url = request.getHost() + request.getPath();
      // 判断不同请求参数类型:0 query参数,1 rest参数, 2使用 body参数
      int queryType = request.getRequestType();
      if (queryType == 0) {
          // query 参数
          HashMap<String, Object> paramMap = new HashMap<>();
          JSONArray jsonArray = JSONArray.parseArray(request.getRequest());
          for (int i=0; i<jsonArray.size(); i++) {
              paramMap.put(jsonArray.getJSONObject(i).get("queryKey").toString(), jsonArray.getJSONObject(i).get("value"));
          }
          if (request.getMethod().equals("get")) {
              String result = HttpRequest.get(url)
                      .form(paramMap)
                      .execute()
                      .body();
              return JSONObject.parseObject(result);
          }
          if (request.getMethod().equals("post")) {
              String result = HttpRequest.post(url)
                      .form(paramMap)
                      .execute()
                      .body();
              return JSONObject.parseObject(result);
          }
      } else if (queryType == 1) {
          // rest参数
          HashMap<String, Object> paramMap = new HashMap<>();
          JSONArray jsonArray = JSONArray.parseArray(request.getRequest());
          for (int i=0; i<jsonArray.size(); i++) {
              paramMap.put(jsonArray.getJSONObject(i).get("restKey").toString(), jsonArray.getJSONObject(i).get("value"));
          }
          // 去掉path后面的参数,还原path
          List<String> list = Arrays.asList(request.getPath().split("/\\{"));
          String orginPath = list.get(0);
          // 解析path中的参数,确认参数拼接顺序
          List<String> resultFindAll = ReUtil.findAll("(?<=\\{)(.+?)(?=\\})", request.getPath(), 0);
          String appendParamPath = "";
          for (String i : resultFindAll) {
              appendParamPath = appendParamPath.concat("/" + paramMap.get(i));
          }
          // 发送请求
          if (request.getMethod().equals("get")) {
              String result = HttpRequest
                      .get(request.getHost() + orginPath + appendParamPath)
                      .execute()
                      .body();
              return JSONObject.parseObject(result);
          }
          if (request.getMethod().equals("post")) {
              String result = HttpRequest
                      .post(request.getHost() + orginPath + appendParamPath)
                      .execute()
                      .body();
              return JSONObject.parseObject(result);
          }
      } else if (queryType == 2) {
          // 请求体
          if (request.getMethod().equals("post")) {
              String reqBody = request.getRequest();
              String result = HttpRequest.post(url)
                      .body(reqBody)
                      .execute().body();
              return JSONObject.parseObject(result);
          }
          // 请求体
          if (request.getMethod().equals("get")) {
              String reqBody = request.getRequest();
              String result = HttpRequest.get(url)
                      .body(reqBody)
                      .execute().body();
              return JSONObject.parseObject(result);
          }
      }
      return null;
  }


乍一看比较多,其实分开看就好:


  • 根据参数类型,分别对于 query、rest、body 的请求参数情况进行处理
  • 在其中每种类型里,又区分了 get、post 方法


简单介绍下其中各种的要点。


(1)query 参数


主要是前面的 2 步:


1268169-20211106213622769-1208121097.png


  • 拿到前端的入参,解析成 JSONArray,内部元素类型又是 JSONObject
  • 遍历 JSONArray,通过jsonArray.getJSONObject(i)方法获取各 JSONObject 的 key,对应前端入参的queryKeyvalue,就是参数名和参数值。
  • 接着发送请求,拿到的返回是一个 String,解析成 JSONObject 返回给 controller


(2)rest 参数


处理 rest 参数稍微麻烦了些,比如:


localhost:8080/bloomtest/module/list/3,最后的3才是参数。


处理过程就像我注视写的:


1268169-20211106214114629-1075585911.png


  • 获取前端传来的参数


首先跟上面一样,获取到前端的参数名和值,放到 HashMap 里,熟悉 python的童鞋就当作放到字典里了。


  • 解析path中的参数,确认参数拼接顺序


因为参数名需要跟 url 里的拼接的值顺序对应上才行,接口里保存的url是这样的:/bloomtest/module/list/{projectId},大括号里的就是参数。


所以这里使用了正则去匹配我要的内容,表达式(?<=\{)(.+?)(?=\})我搜的,具体我也不熟悉,后续再学习。


ReUtil.findAll方法也是来自于 hutool 框架,可以查找到所有符合表达式的内容,返回是一个数组。


然后遍历这个数组,把里面的参数逐个拼接到一个空字符串里appendParamPath:


String appendParamPath = "";
  for (String i : resultFindAll) {
      appendParamPath = appendParamPath.concat("/" + paramMap.get(i));
  }


  • 去掉path后面的参数,还原path

因为前端传过来的 path 是/bloomtest/module/list/{projectId},需要去掉最后的/{projectId}才可以使用。


List<String> list = Arrays.asList(request.getPath().split("/\\{"));
  String orginPath = list.get(0);


使用了字符串分割split方法,返回的是一个String[]数组,又通过Arrays.asList进一步做了转化,就可以使用get(0)获取第一个使用了,也就是/bloomtest/module/list


前面都齐了,就可以发送请求了,注意最终请求的 url 还是要拼接一下:


request.getHost() + orginPath + appendParamPath


(3)请求体


这个最简单,前端传过来的 json 字符串直接传入即可:


if (request.getMethod().equals("post")) {
      String reqBody = request.getRequest();
      String result = HttpRequest.post(url)
              .body(reqBody)
              .execute().body();
      return JSONObject.parseObject(result);
  }


要注意的是,这里用的 JSONObject 是来自fastjson,之前用 hutool 带的处理,会有报错,搞了好一会。


1268169-20211106220623846-1819752173.png


三、前端实现


我这里是整个功能开发完成后进行整理的,实际上,后端接口逻辑不是一次性写完的。先写好一个可以前端调得通的接口,然后一点点前后调试完成。


前端这里做的事情不多,在【发送】按钮上绑定一个点击实践,调用后端开发好的接口。


1268169-20211106220028730-106322764.png


方法apiTestRun内部,主要是处理请求入参,调用请求,处理返回即可:


1268169-20211106220112294-600658398.png


红框里是调用接口的部分,前面的是处理入参。这里的 3 个判断是看目前点击了哪个 tab,然后传对应入参类型给接口。


接下来测试下功能OK。


四、修改遗留 bug


在测试功能的时候,发现了几个问题。大概表现都是因为前端参数赋值,或者没重置干净导致的。


1268169-20211106220437647-962847943.png


增加和修改了一些代码,具体不贴了,需要最新代码的可以联系我,直接发给你参考。

相关文章
|
1月前
|
运维
【运维基础知识】用dos批处理批量替换文件中的某个字符串(本地单元测试通过,部分功能有待优化,欢迎指正)
该脚本用于将C盘test目录下所有以t开头的txt文件中的字符串“123”批量替换为“abc”。通过创建批处理文件并运行,可实现自动化文本替换,适合初学者学习批处理脚本的基础操作与逻辑控制。
134 56
|
1月前
|
测试技术
Appscan手工探索、手工测试功能实战
Appscan手工探索、手工测试功能实战
|
2月前
|
JSON 移动开发 监控
快速上手|HTTP 接口功能自动化测试
HTTP接口功能测试对于确保Web应用和H5应用的数据正确性至关重要。这类测试主要针对后台HTTP接口,通过构造不同参数输入值并获取JSON格式的输出结果来进行验证。HTTP协议基于TCP连接,包括请求与响应模式。请求由请求行、消息报头和请求正文组成,响应则包含状态行、消息报头及响应正文。常用的请求方法有GET、POST等,而响应状态码如2xx代表成功。测试过程使用Python语言和pycurl模块调用接口,并通过断言机制比对实际与预期结果,确保功能正确性。
247 3
快速上手|HTTP 接口功能自动化测试
|
3月前
|
Web App开发 敏捷开发 测试技术
自动化测试之美:使用Selenium WebDriver进行网页功能验证
【8月更文挑战第29天】在数字时代,软件质量是企业竞争力的关键。本文将深入探讨如何通过Selenium WebDriver实现自动化测试,确保网页应用的可靠性和性能。我们将从基础设置到编写测试用例,逐步引导读者掌握这一强大的测试工具,同时分享实战经验,让测试不再是开发的负担,而是质量保证的利器。
|
6天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
34 3
|
1月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
57 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
237 7
Jmeter实现WebSocket协议的接口测试方法
|
1月前
|
JavaScript 前端开发 API
vue尚品汇商城项目-day02【9.Home组件拆分+10.postman测试接口】
vue尚品汇商城项目-day02【9.Home组件拆分+10.postman测试接口】
40 0
|
2月前
|
JavaScript 前端开发 测试技术
ChatGPT与接口测试
ChatGPT与接口测试,测试通过
48 5
|
3月前
|
网络协议 测试技术 网络安全
Python进行Socket接口测试的实现
在现代软件开发中,网络通信是不可或缺的一部分。无论是传输数据、获取信息还是实现实时通讯,都离不开可靠的网络连接和有效的数据交换机制。而在网络编程的基础中,Socket(套接字)技术扮演了重要角色。 Socket 允许计算机上的程序通过网络进行通信,它是网络通信的基础。Python 提供了强大且易于使用的 socket 模块,使开发者能够轻松地创建客户端和服务器应用,实现数据传输和交互。 本文将深入探讨如何利用 Python 编程语言来进行 Socket 接口测试。我们将从基础概念开始介绍,逐步引导大家掌握创建、测试和优化 socket 接口的关键技能。希望本文可以给大家的工作带来一些帮助~