基础的HTTPClient搭建注意事项(中)

项目结构更新:


基础的HTTPClient搭建注意事项(中)_第1张图片
结构图V1.1

修改了replaceBodyParamsreplaceParams,更加直观

新加了asserExpected函数作为判断断言类似的,接口测试不只要测成功的例子,也要测失败的例子。当初真的是想当然了,这个函数我遇到了些麻烦,会在文章结尾说明下。


首先,放上该项目所用到的包依赖,以免用错包就尴尬了

package com.mhc.wey.core.httpInterface;


import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import com.mhc.wey.dal.model.HttpInterfaceCaseDO;

import com.subaru.common.entity.BizResult;

import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

import org.apache.http.*;

import org.apache.http.client.HttpRequestRetryHandler;

import org.apache.http.client.config.RequestConfig;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.client.protocol.HttpClientContext;

import org.apache.http.conn.ConnectTimeoutException;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.conn.ssl.X509HostnameVerifier;

import org.apache.http.cookie.Cookie;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.impl.client.LaxRedirectStrategy;

import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import org.apache.http.message.BasicHeader;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.protocol.HttpContext;

import org.apache.http.ssl.SSLContextBuilder;

import org.apache.http.ssl.TrustStrategy;

import org.apache.http.util.EntityUtils;

import org.springframework.context.annotation.Lazy;

import org.springframework.stereotype.Service;


import javax.net.ssl.*;

import java.io.IOException;

import java.io.InterruptedIOException;

import java.net.UnknownHostException;

import java.security.GeneralSecurityException;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

import java.util.*;


用到的装饰器:

@Service

@Slf4j

@Lazy


上面用到了两个我司自定义的包,已经标注出来了

com.mhc.wey.dal.model.HttpInterfaceCaseDO为接口测试用例数据(数据库导入)

com.subaru.common.entity.BizResult为消息返回的对象


execute代码如下

BizResult bizResult =null;

//执行请求

BizResult executeHttpRequestResult = executeEncapsulation(httpInterfaceCaseDO);

if (! executeHttpRequestResult.isSuccess()) {

return executeHttpRequestResult;

}

CloseableHttpResponse response = (CloseableHttpResponse) executeHttpRequestResult.getData();

log.info("开始解析Response");

//解析response

try {

if (assertExpected(response, httpInterfaceCaseDO)) {

setReplaceMap(httpInterfaceCaseDO.getResponseBodyTransferedParams(), response);

    }else {

bizResult = BizResult.create(null,false,"9999","assertExpected返回错误");

    }

}catch (NullPointerException e) {

bizResult = BizResult.create(e,false,"9999","获取response实体时出现Exception");

}

finally {

try {

//关闭连接

        response.close();

        client.close();

    }catch (Exception e) {

bizResult = BizResult.create("BOOM!!!",true,"1000","HTTPClient没有关闭");

    }

if (bizResult ==null) {

bizResult = BizResult.create("OK",true,"1000","接口测试通过");

    }

}

return bizResult;


函数的逻辑十分清晰

- 先执行请求

- 断言返回值是否符合预期

- 满足断言,则处理Response, 获取响应对象中部分参数的值


executeEncapsulation代码如下

//参数替换

BizResult replaceHeaderParamsResult = replaceParams(httpInterfaceCaseDO.getRequestHeader());

if (! replaceHeaderParamsResult.isSuccess()) {

return replaceHeaderParamsResult;

}else {

httpInterfaceCaseDO.setRequestHeader(replaceHeaderParamsResult.getData().toString());

}

BizResult replaceBodyParamsResult = replaceParams(httpInterfaceCaseDO.getRequestBody());

if (! replaceBodyParamsResult.isSuccess()) {

return replaceBodyParamsResult;

}else {

httpInterfaceCaseDO.setRequestBody(replaceBodyParamsResult.getData().toString());

}

//参数校验

BizResult initResult = init(httpInterfaceCaseDO);

if (! initResult.isSuccess()) {

return initResult;

}

return executeHttpRequest(httpInterfaceCaseDO);


替换请求头和请求体的值,再进行值检验


replaceParams代码如下

if (StringUtils.isNoneBlank(str)) {

JSONObject bodyObject = JSON.parseObject(str);

            for (String key:

bodyObject.keySet()) {

String keyget = (String) bodyObject.get(key);

                if (keyget.startsWith("$")) {

String replacekey = keyget.substring(keyget.indexOf("{") +1, keyget.indexOf("}")).trim();

                    if (StringUtils.isNoneBlank(replacekey)) {

String value = (String)ReplaceMap.get(replacekey);

                        if (StringUtils.isBlank(value)) {

return BizResult.create(null,false,"9999","ReplaceMap取值异常");

                        }

//                        替换请求体内的变量

                        bodyObject.replace(key, value);

                    }else {

return BizResult.create(null,false,"9999","ReplaceMap取值异常");

                    }

}

}

}

return BizResult.create(str,true,"1000","替换RequestBody里面的转义字符成功");


这里是直接传待转换字符串进来,这个字符串为了方便默认是JSONString,然后就是正则处理下。

这里要注意的是

String value = (String)ReplaceMap.get(replacekey);

因为会有其他测试人员在接口测试时,打错了变量名,这样的场景是我们要去避免的


init代码如下

    if (! checkParams(httpInterfaceCaseDO)) {

return BizResult.create("CheckParameters not pass",false,"9999","Request参数缺失");

}

//RequestMethod检验

if (! (httpInterfaceCaseDO.getRequestMethod().toUpperCase().contentEquals(HttpEnum.GET ) || httpInterfaceCaseDO.getRequestMethod().toUpperCase().contentEquals(HttpEnum.POST ))) {

return BizResult.create("RequestMethod异常",false,"9999","RequestMethod异常");

}

if (StringUtils.isNotEmpty(httpInterfaceCaseDO.getDataFormat()) && StringUtils.isNotBlank(httpInterfaceCaseDO.getDataFormat().trim())) {

if (! (httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.STRING) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.JSON) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.FORM) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.MEDIA))) {

//如果没有参数类型,默认设置为Srting

        httpInterfaceCaseDO.setDataFormat(HttpEnum.STRING);

    }

}

getSessionId(httpInterfaceCaseDO);

return BizResult.create("continue",true,"6666","初始化测试数据成功");


getSessionId代码如下

    String sessionId ="";

        String body ="";

        try {

if (context ==null) {

log.info("context为空");

            }

List listOfCookies =context.getCookieStore().getCookies();

            for (Cookie cookie:

listOfCookies) {

if (“这里不给看哦”.equals(cookie.getName())) {

return BizResult.create("", true, "1000", "已有sessionId,直接通过");

                }

}

}catch (Exception e) {

log.info("日常没登陆");

        }

if (! httpInterfaceCaseDO.getRequestUrl().contains("login")) {

return BizResult.create(null, true, "9999", "未登录");

        }else {

//涉及我司有关内容,已删除

BizResult executeResult = executeHttpRequest(httpInterfaceCaseDO);

            if (! executeResult.isSuccess()) {

return executeResult;

            }

CloseableHttpResponse response = (CloseableHttpResponse) executeResult.getData();

            if (response.getStatusLine().getStatusCode() != HttpEnum.STATUS_OK) {

return BizResult.create(null, false, "9999", "请求失败");

            }

}

return BizResult.create(sessionId, true, "1000", "请求成功");


这里主要依赖了HTTPContext保持连接的特性,在单线程内,只要不close掉的话,会一直存储Cookie和其他需要的值


executeHttpRequest代码如下

    CloseableHttpResponse response =null;

        HttpEntity entity =null;

        //请求协议

        String requestType = httpInterfaceCaseDO.getRequestUrl().substring(0, httpInterfaceCaseDO.getRequestUrl().indexOf(":", 1)).trim();

//        实例化httpclient

        BizResult requestResult = switchType(requestType);

        if (!requestResult.isSuccess()) {

return requestResult;

        }

//        判断请求类型

        try {

switch (httpInterfaceCaseDO.getRequestMethod().toUpperCase()) {

case HttpEnum.GET:

HttpGet httpGet =null;

//              判断是否有请求体

                    if (StringUtils.isNotEmpty(httpInterfaceCaseDO.getRequestBody()) && StringUtils.isNotBlank(httpInterfaceCaseDO.getRequestBody().trim())) {

String body = httpInterfaceCaseDO.getRequestBody().trim();

//                    url为转换后的请求体

                        StringBuilder url =new StringBuilder();

//                    判断请求体是否是json格式的数据

                        if (body.startsWith("{")) {

JSONObject jsonObject = JSON.parseObject(body);

                            for (String key :

jsonObject.keySet()) {

if (StringUtils.isNotEmpty(url)) {

url.append("&");

                                }

url.append(String.format("%s?%s", key, jsonObject.getString(key)));

                            }

}

//                          有请求体的GET

                        httpGet =new HttpGet(String.format("%s?%s", httpInterfaceCaseDO.getRequestUrl(), url.toString()));

                    }else {

//                        无请求体的GET

                        httpGet =new HttpGet(httpInterfaceCaseDO.getRequestUrl());

                    }

if (StringUtils.isNoneBlank(httpInterfaceCaseDO.getRequestHeader())) {

JSONObject headerObject = JSON.parseObject(httpInterfaceCaseDO.getRequestHeader());

                        for (String key :

headerObject.keySet()) {

httpGet.addHeader(key, (String) headerObject.get(key));

                        }

}

for (Header header :

defaultHeader()) {

httpGet.addHeader(header);

                    }

//执行http get请求

                    response =client.execute(httpGet, context);

break;

                case HttpEnum.POST:

HttpPost httpPost =new HttpPost(httpInterfaceCaseDO.getRequestUrl());

                    if (StringUtils.isEmpty(httpInterfaceCaseDO.getDataFormat())) {

//                  POST方式需要DataFormat字段,无此字段则抛出异常

                        throw new ValueException("POST没有DataFormat字段");

                    }

// 创建请求参数

                    switch (httpInterfaceCaseDO.getDataFormat().toUpperCase()) {

case HttpEnum.STRING:

entity =new StringEntity(httpInterfaceCaseDO.getRequestBody(), "utf-8");

break;

                        case HttpEnum.FORM:

List body =new ArrayList();

                            JSONObject jsonObject = JSON.parseObject(httpInterfaceCaseDO.getRequestBody());

                            for (String key :

jsonObject.keySet()) {

body.add(new BasicNameValuePair(key, jsonObject.getString(key)));

                            }

entity =new UrlEncodedFormEntity(body, "utf-8");

break;

//                      这里暂时不动,考虑下Entity的类型

                        case HttpEnum.MEDIA:

//获取分隔符

                            String[] array = httpInterfaceCaseDO.getRequestHeader().split("=");

                            String bound = array[1].substring(1, array[1].lastIndexOf("\""));

                            //添加分割线

//                      entity = new MultipartRequestEntity();

                            break;

                        default:

break;

                    }

httpPost.setEntity(entity);

                    if (StringUtils.isNoneBlank(httpInterfaceCaseDO.getRequestHeader())) {

JSONObject headerObject = JSON.parseObject(httpInterfaceCaseDO.getRequestHeader());

                        for (String key :

headerObject.keySet()) {

httpPost.addHeader(key, (String) headerObject.get(key));

                        }

}

for (Header header :

defaultHeader()) {

httpPost.addHeader(header);

                    }

//执行http post请求

                    response =client.execute(httpPost, context);

break;

                default:

break;

                }

}catch(IOException | NullPointerException e){

return BizResult.create(e, false, "9999", "请求异常 -  " + httpInterfaceCaseDO.getRequestMethod().toUpperCase());

        }

return BizResult.create(response, true, "1000", "请求成功");


这块代码也是我负责的项目中最长最重要的一块,你们可以看到我POST的MEDIA方式,是还没写完的,不好意思,写到一半的时候,被告知我司的接口需要用到该场景的次数极少,故不了了之,代码长就长在对String的处理,其实像

JSONObject jsonObject = JSON.parseObject(body);

for (String key :

headerObject.keySet()) {

httpPost.addHeader(key, (String) headerObject.get(key));

}

这种代码是可以的整合的,但写完就不想动了。。。

不是支持MarkDown的么,写完一发,看到格式不对,真是哔到gou了

暂时先到这,再熬夜怕是要变强了

你可能感兴趣的:(基础的HTTPClient搭建注意事项(中))