前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >接口自动化测试平台:接口内容的简单执行

接口自动化测试平台:接口内容的简单执行

作者头像
软件测试君
发布2019-11-15 20:48:55
7830
发布2019-11-15 20:48:55
举报
文章被收录于专栏:测试人生测试人生

一、涉及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层
代码语言:javascript
复制
@Override
 public ResponseVo excuteRequest(Integer[] ids) {

     ResponseVo responseVo = new ResponseVo();

     // 获取当前需执行的所有case
     List<TestCase> caseList = apiTestCaseMapper.selectTestCaseListByIds(ids);
     // 遍历caseList,进行http请求
     for (TestCase testCase:caseList){
         // 保存响应结果
         String result = "";
         Response response = ApiTestUtils.doRequest(testCase, GLOBAL_COLLECTION_ID);
         try {
             result = response.body().string();
         } catch (IOException e) {
             e.printStackTrace();
         }

         // 保存变量, 调试执行时可以忽略此方法
         ApiTestUtils.saveVariable(result, testCase, GLOBAL_COLLECTION_ID);

         // 判断是否通过了所有校验条件
         if (ApiTestUtils.verifyResult(result, testCase, GLOBAL_COLLECTION_ID)){
             testCase.setStatus(Boolean.TRUE);
         } else {
             testCase.setStatus(Boolean.FALSE);
         }
         testCase.setResult(result);

         // 更新数据库保存的信息
         setJsonValue(testCase);
         apiTestCaseMapper.updateCase(testCase);

         // 将执行后的结果返回给前端
         responseVo.setIsSuccess(Boolean.TRUE);
         responseVo.setResult(testCase);

     }

     return responseVo;
 }
mapper.xml
代码语言:javascript
复制
<select id="selectTestCaseListByIds" resultMap="caseList">
    select * from apitest_testcase
    where id in
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>
ApiTestUtils

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

代码语言:javascript
复制
@Slf4j
public class ApiTestUtils {


    /**
     * @param testCase 传入完整的case数据
     * @param collectionId 集合id,如果传入0则表示为接口调试执行
     * @return Response返回结果
     */
    public static Response doRequest(TestCase testCase, Integer collectionId){

        String url = "http://" + getVariable(testCase.getApiUrl(), collectionId);

        if (null != testCase.getApiPort()){
            url += ":" + String.valueOf(testCase.getApiPort());
        }
        if (!testCase.getApiPath().isEmpty()){
            url += getVariable(testCase.getApiPath(),collectionId);
        }

        // 请求方式: POST/GET
        String apiMethod = testCase.getApiMethod();

        // 请求类型:1.json  2.url form
        int bodyType = testCase.getBodyType();
        String body = "";

        // 连接超时、写入超时、读取超时,均设置为30s,这里不做展开讨论,有兴趣的同学可以搜一下okhttp的用法
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(Config.connectTimeout, TimeUnit.SECONDS)
                .writeTimeout(Config.writeTimeout,TimeUnit.SECONDS)
                .readTimeout(Config.readTimeout, TimeUnit.SECONDS)
                .build();

        Request.Builder builder = new Request.Builder();

        // 设置header
        List<RequestHeaders> headersList = JSON.parseArray(testCase.getHeaderValue(), RequestHeaders.class);
        for (RequestHeaders headers:headersList){
            builder.header(headers.getHeaderKey(), getVariable(headers.getHeaderValue(), collectionId));

        }

        // 设置body、mediaType
        String mediaTypeValue = "";
        if (bodyType == 1){
            mediaTypeValue = "application/json;charset=UTF-8";
            body = testCase.getJsonValue();
        } else if (bodyType == 2){
            mediaTypeValue = "application/x-www-form-urlencoded;charset=utf-8";
            //TODO urlfrom的body处理
        }

        // 如果前端没有传body,讲body设置为空string
        if (body == null){
            body = "";
        } else {
            body = getVariable(body, collectionId);
        }

        Request request = null;
        if (apiMethod.equals("POST")){
            RequestBody requestBody =RequestBody.create(MediaType.parse(mediaTypeValue), body);
            request = builder.url(url).post(requestBody).build();
        } else if(apiMethod.equals("GET")){
            request = builder.url(url).get().build();
        }

        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return response;

    }

    /**
     *
     * @param string 变量名
     * @param collectionId 集合id,:为0时只读全局变量,非0时读了全局变量再读集合内变量
     * @return 变量值
     */
    private static String getVariable(String string,Integer collectionId){

        HashMap<String,String> variableMap = ApiTestConfig.globalVariableMap;


        // 如果为集合执行,会再次获取集合内变量
        if (collectionId != 0){
            variableMap.putAll(ApiTestConfig.collectionVariableMap);
        }

        // 查询string中是否有${KEY}格式的数据,如果有则将其替换为VALUE
        if (!string.isEmpty()){
            String reg = "\\$\\{.*?}";
            Pattern p = Pattern.compile(reg);
            Matcher m = p.matcher(string);
            // 遍历替换所有的变量
            while (m.find()){
                String key = m.group().replace("${","").replace("}","");
                if (variableMap.containsKey(key)){
                    string = string.replace(m.group(),variableMap.get(key));
                }
            }
            return string;
        } else {
            return "";
        }

    }

    /** 保存变量 */
    public static void saveVariable(String result, TestCase testCase, Integer collectionId) {
        // 调试执行时可以忽略此方法

    }

    /**
     * 遍历ExpectedList,只要有校验不通过的条件测抛FALSE
     */
    public static Boolean verifyResult(String responseResult, TestCase testCase, Integer collectionId){

        List<Expected> ExpectedList = JSON.parseArray(testCase.getExpectedListValue(), Expected.class);
        if (ExpectedList.size() == 0){
            if (collectionId != 0){
                Assert.assertTrue(Boolean.TRUE);
            }
            return Boolean.TRUE;
        }
        Boolean bool = Boolean.FALSE;

        for (Expected exp:ExpectedList){
            // 提取方式:1.jsonPath  2.正则表达式
            int extractMethod = exp.getExtractMethod();
            String extractRule = exp.getExtractRule();
            // 校验方式:1.equasl 2.contains
            int compareType = exp.getCompareType();
            String expectedValue = exp.getExpectedValue();

            // 实际获取结果
            String actualRes = "";
            if (extractMethod == 1){
                try {
                    // 这里取到的值如果是bool时,强转会抛错,所以需要用object接一下,再转String
                    Object o = JsonPath.read(responseResult, extractRule);
                    actualRes = String.valueOf(o);
                } catch (Exception e){
                    if (collectionId != 0){
                        Reporter.log("接口返回结果为:" + responseResult);
                        Assert.fail("预期值取值失败");
                    }

                    return Boolean.FALSE;
                }
            } else if (extractMethod == 2){
                try {
                    Pattern p = Pattern.compile(extractRule);
                    Matcher m = p.matcher(responseResult);
                    if (m.find()){
                        actualRes = m.group();
                    }
                } catch (Exception e){
                    if (collectionId != 0){
                        Assert.fail("预期值取值异常");
                    }
                    return Boolean.FALSE;
                }

            }

            // 对比预期结果
            if (compareType == 1){
                if (collectionId != 0){
                    Assert.assertEquals(actualRes, expectedValue);
                }
                if (actualRes.equals(expectedValue)){
                    bool = Boolean.TRUE;
                }
            } else if (compareType == 2){
                if (actualRes.contains(expectedValue)){
                    bool = Boolean.TRUE;
                } else {
                    if (collectionId != 0){
                        Assert.fail("预期值:" + expectedValue + "不存在与期望值" + actualRes + "中");
                    }
                }
            }

        }

        return bool;
    }
}

3、将结果进行储存和反馈给前端。

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

代码语言:javascript
复制
 // 自己封装的方法,给header,formValue,variableList,expectedList等字段赋值
 setJsonValue(testCase);
 // 更新数据库保存的信息
 apiTestCaseMapper.updateCase(testCase);

 // 将执行后的结果返回给前端
 responseVo.setIsSuccess(Boolean.TRUE);
 responseVo.setResult(testCase);

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

4、前端对数据进行处理

在列表进行批量执行时,拿到后端返回的isSuccess=true时,则执行刷新列表,获取最新的每个接口的执行状态。

在进行单接口调试时,从result中的testCase信息获取接口响应结果及校验结果,重新渲染页面。

上述过程,将前端传数据然后读sql的过程转变为xml驱动testng进行执行,可以替换成一个接口测试框架。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-14,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 软件测试君 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • service层
  • mapper.xml
  • ApiTestUtils
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com