接口测试平台:Http请求的简单执行(旧版已废弃)

柔情只为你懂 2023-05-30 15:55 182阅读 0赞

本文是上文《接口测试平台:接口内容的设计》的具体执行部分。
涉及jar包如下:

  • mybatis-spring-boot-starter 1.3.0
  • lombok 1.16.16
  • okhttp 3.10.0
  • json-path 2.4.0

大概逻辑如下:

  1. 前端选择执行

    • 可以在列表页进行多选,执行
      在这里插入图片描述
    • 单接口的调试执行
      在这里插入图片描述
  2. 后端在数据库逐读取所有case的具体信息,逐条执行case。

  3. 将结果进行储存和反馈给前端。
  4. 前端对数据进行处理,如果是列表的批量执行,只会刷新case的最后执行状态,如果是单条case的调试执行,会渲染最新的result(接口返回结果)

具体实现思路如下:

1.前端选择执行

在这里插入图片描述
前端在点击执行时,会进行一次请求,像后端传一个id的list(id即为case在数据库中的存储id)

2.后端在数据库逐读取所有case的具体信息,逐条执行case。
  • service层

    @Override
    public ResponseVo excuteRequest(Integer[] ids) {

    1. ResponseVo responseVo = new ResponseVo();
    2. // 获取当前需执行的所有case
    3. List<TestCase> caseList = apiTestCaseMapper.selectTestCaseListByIds(ids);
    4. // 遍历caseList,进行http请求
    5. for (TestCase testCase:caseList){
    6. // 保存响应结果
    7. String result = "";
    8. Response response = ApiTestUtils.doRequest(testCase, GLOBAL_COLLECTION_ID);
    9. try {
    10. result = response.body().string();
    11. } catch (IOException e) {
    12. e.printStackTrace();
    13. }
    14. // 保存变量, 调试执行时可以忽略此方法
    15. ApiTestUtils.saveVariable(result, testCase, GLOBAL_COLLECTION_ID);
    16. // 判断是否通过了所有校验条件
    17. if (ApiTestUtils.verifyResult(result, testCase, GLOBAL_COLLECTION_ID)){
    18. testCase.setStatus(Boolean.TRUE);
    19. } else {
    20. testCase.setStatus(Boolean.FALSE);
    21. }
    22. testCase.setResult(result);
    23. // 更新数据库保存的信息
    24. setJsonValue(testCase);
    25. apiTestCaseMapper.updateCase(testCase);
    26. // 将执行后的结果返回给前端
    27. responseVo.setIsSuccess(Boolean.TRUE);
    28. responseVo.setResult(testCase);
    29. }
    30. return responseVo;

    }

  • mapper.xml

  • ApiTestUtils
    这里有一个collectionId(集合id),用于后面的集合执行,此处全部默认为0即可。

    @Slf4j
    public class ApiTestUtils {

  1. /** * @param testCase 传入完整的case数据 * @param collectionId 集合id,如果传入0则表示为接口调试执行 * @return Response返回结果 */
  2. public static Response doRequest(TestCase testCase, Integer collectionId){
  3. String url = "http://" + getVariable(testCase.getApiUrl(), collectionId);
  4. if (null != testCase.getApiPort()){
  5. url += ":" + String.valueOf(testCase.getApiPort());
  6. }
  7. if (!testCase.getApiPath().isEmpty()){
  8. url += getVariable(testCase.getApiPath(),collectionId);
  9. }
  10. // 请求方式: POST/GET
  11. String apiMethod = testCase.getApiMethod();
  12. // 请求类型:1.json 2.url form
  13. int bodyType = testCase.getBodyType();
  14. String body = "";
  15. // 连接超时、写入超时、读取超时,均设置为30s,这里不做展开讨论,有兴趣的同学可以搜一下okhttp的用法
  16. OkHttpClient client = new OkHttpClient.Builder()
  17. .connectTimeout(Config.connectTimeout, TimeUnit.SECONDS)
  18. .writeTimeout(Config.writeTimeout,TimeUnit.SECONDS)
  19. .readTimeout(Config.readTimeout, TimeUnit.SECONDS)
  20. .build();
  21. Request.Builder builder = new Request.Builder();
  22. // 设置header
  23. List<RequestHeaders> headersList = JSON.parseArray(testCase.getHeaderValue(), RequestHeaders.class);
  24. for (RequestHeaders headers:headersList){
  25. builder.header(headers.getHeaderKey(), getVariable(headers.getHeaderValue(), collectionId));
  26. }
  27. // 设置body、mediaType
  28. String mediaTypeValue = "";
  29. if (bodyType == 1){
  30. mediaTypeValue = "application/json;charset=UTF-8";
  31. body = testCase.getJsonValue();
  32. } else if (bodyType == 2){
  33. mediaTypeValue = "application/x-www-form-urlencoded;charset=utf-8";
  34. //TODO urlfrom的body处理
  35. }
  36. // 如果前端没有传body,讲body设置为空string
  37. if (body == null){
  38. body = "";
  39. } else {
  40. body = getVariable(body, collectionId);
  41. }
  42. Request request = null;
  43. if (apiMethod.equals("POST")){
  44. RequestBody requestBody =RequestBody.create(MediaType.parse(mediaTypeValue), body);
  45. request = builder.url(url).post(requestBody).build();
  46. } else if(apiMethod.equals("GET")){
  47. request = builder.url(url).get().build();
  48. }
  49. Response response = null;
  50. try {
  51. response = client.newCall(request).execute();
  52. } catch (IOException e) {
  53. e.printStackTrace();
  54. }
  55. return response;
  56. }
  57. /** * * @param string 变量名 * @param collectionId 集合id,:为0时只读全局变量,非0时读了全局变量再读集合内变量 * @return 变量值 */
  58. private static String getVariable(String string,Integer collectionId){
  59. HashMap<String,String> variableMap = ApiTestConfig.globalVariableMap;
  60. // 如果为集合执行,会再次获取集合内变量
  61. if (collectionId != 0){
  62. variableMap.putAll(ApiTestConfig.collectionVariableMap);
  63. }
  64. // 查询string中是否有${KEY}格式的数据,如果有则将其替换为VALUE
  65. if (!string.isEmpty()){
  66. String reg = "\\$\\{.*?}";
  67. Pattern p = Pattern.compile(reg);
  68. Matcher m = p.matcher(string);
  69. // 遍历替换所有的变量
  70. while (m.find()){
  71. String key = m.group().replace("${","").replace("}","");
  72. if (variableMap.containsKey(key)){
  73. string = string.replace(m.group(),variableMap.get(key));
  74. }
  75. }
  76. return string;
  77. } else {
  78. return "";
  79. }
  80. }
  81. /** 保存变量 */
  82. public static void saveVariable(String result, TestCase testCase, Integer collectionId) {
  83. // 调试执行时可以忽略此方法
  84. }
  85. /** * 遍历ExpectedList,只要有校验不通过的条件测抛FALSE */
  86. public static Boolean verifyResult(String responseResult, TestCase testCase, Integer collectionId){
  87. List<Expected> ExpectedList = JSON.parseArray(testCase.getExpectedListValue(), Expected.class);
  88. if (ExpectedList.size() == 0){
  89. if (collectionId != 0){
  90. Assert.assertTrue(Boolean.TRUE);
  91. }
  92. return Boolean.TRUE;
  93. }
  94. Boolean bool = Boolean.FALSE;
  95. for (Expected exp:ExpectedList){
  96. // 提取方式:1.jsonPath 2.正则表达式
  97. int extractMethod = exp.getExtractMethod();
  98. String extractRule = exp.getExtractRule();
  99. // 校验方式:1.equasl 2.contains
  100. int compareType = exp.getCompareType();
  101. String expectedValue = exp.getExpectedValue();
  102. // 实际获取结果
  103. String actualRes = "";
  104. if (extractMethod == 1){
  105. try {
  106. // 这里取到的值如果是bool时,强转会抛错,所以需要用object接一下,再转String
  107. Object o = JsonPath.read(responseResult, extractRule);
  108. actualRes = String.valueOf(o);
  109. } catch (Exception e){
  110. if (collectionId != 0){
  111. Reporter.log("接口返回结果为:" + responseResult);
  112. Assert.fail("预期值取值失败");
  113. }
  114. return Boolean.FALSE;
  115. }
  116. } else if (extractMethod == 2){
  117. try {
  118. Pattern p = Pattern.compile(extractRule);
  119. Matcher m = p.matcher(responseResult);
  120. if (m.find()){
  121. actualRes = m.group();
  122. }
  123. } catch (Exception e){
  124. if (collectionId != 0){
  125. Assert.fail("预期值取值异常");
  126. }
  127. return Boolean.FALSE;
  128. }
  129. }
  130. // 对比预期结果
  131. if (compareType == 1){
  132. if (collectionId != 0){
  133. Assert.assertEquals(actualRes, expectedValue);
  134. }
  135. if (actualRes.equals(expectedValue)){
  136. bool = Boolean.TRUE;
  137. }
  138. } else if (compareType == 2){
  139. if (actualRes.contains(expectedValue)){
  140. bool = Boolean.TRUE;
  141. } else {
  142. if (collectionId != 0){
  143. Assert.fail("预期值:" + expectedValue + "不存在与期望值" + actualRes + "中");
  144. }
  145. }
  146. }
  147. }
  148. return bool;
  149. }
  150. }
3.将结果进行储存和反馈给前端。

service层这四行代码,进行了处理

  1. // 自己封装的方法,给header,formValue,variableList,expectedList等字段赋值
  2. setJsonValue(testCase);
  3. // 更新数据库保存的信息
  4. apiTestCaseMapper.updateCase(testCase);
  5. // 将执行后的结果返回给前端
  6. responseVo.setIsSuccess(Boolean.TRUE);
  7. responseVo.setResult(testCase);

这里只返回了最后一条case的信息

4.前端对数据进行处理

在列表进行批量执行时,拿到后端返回的isSuccess=true时,则执行刷新列表,获取最新的每个接口的执行状态。
在进行单接口调试时,从result中的testCase信息获取接口响应结果及校验结果,重新渲染页面。

上述过程,将前端传数据然后读sql的过程转变为xml驱动testng进行执行,可以替换成一个接口测试框架。
下篇文章会讲解在多接口测试中,如何控制接口与接口间的数据依赖。有疑问的小伙伴欢迎在文章下方留言,我会根据问题不断优化文章内容!

发表评论

表情:
评论列表 (有 0 条评论,182人围观)

还没有评论,来说两句吧...

相关阅读