专栏首页测试人生接口自动化测试平台:接口内容的简单执行

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

一、涉及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) {

     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

<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即可。

@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层这四行代码,进行了处理

 // 自己封装的方法,给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进行执行,可以替换成一个接口测试框架。

本文分享自微信公众号 - 软件测试君(backlight2018),作者:简单随风

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 接口自动化落地(一:MySQL+MyBatis实现对测试用例数据的读取)

    本篇文章讲解TestNG+MySQL+MyBatis+ExtentReports实现对测试用例数据的读取,下面放出所有配置文件的目录方便下文理解。

    软件测试君
  • 是什么让测试工作如此辛苦?

    大家好,我是测试君,下面来分享一篇文章《是什么让测试工作如此辛苦?》,希望此文能够让你有所收获,当然也希望能够结识一些在测试路上能够一起前行的朋友。

    软件测试君
  • 接口测试平台:支持函数助手

    因为接口的需求,需要支持类似于Jmeter中函数助手的功能。 以以下两个函数进行举例:

    软件测试君
  • 关于wsgi协议的理解

    首先要了解 WSGI 规范的概念,WSGI(Web Server Gateway Interface)规范描述了web server(Gunicorn,uWSG...

    步履不停凡
  • 关于项目里面的硬核漏洞(找不到漏洞看这里)

    以下漏洞过于硬核又比较相对容易挖掘,毕竟我是实习两年半的低危文档工程师。(可能写的不太全)适合在渗透里面没有找到漏洞,以防尴尬。

    Aran
  • Q100 Same Tree

    Given two binary trees, write a function to check if they are the same or not. T...

    echobingo
  • Python3经典100例(③)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    村雨遥
  • Zookeeper详解(十):Pytho

    关于Watcher,网上很多帖子都是通过装饰器的方式实现的,其实我上面的方式和装饰器是一样的,只是形式不同罢了。功能都能实现,只是用装饰器有时候会不方便。

    用户2398817
  • Golang Leetcode 796. Rotate String.go

    更多内容请移步我的repo:https://github.com/anakin/golang-leetcode

    anakinsun
  • 20+最好的持续集成工具

    整理了20多款持续集成工具,这是作为软件测试人员需要了解的,也是在构建持续质量改进时,需要进行选型的基础设施工具。

    苦叶子

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动