在测试过程中,有一个重要的工作就是保存记录“现场”,以方便开发人员更快发现BUG解决问题。在接口测试中更是如此,如果开发人员能够根据BUG的信息直接复现请求,是一件很方便的事情。为此我想了一个再框架中增加保存HTTPrequestbase和CloseableHttpResponse两个对象的功能,其中主要是HTTPrequestbase的信息,CloseableHttpResponse以响应内容为主,因为每次请求我都会把必要信息(host,API,HTTP code,响应code,响应时间等等记录)。

下面是更新过的funrequest类的代码,更新内容时后面几个静态方法:

package com.fun.frame.httpclient

import com.fun.base.bean.RequestInfo
import com.fun.base.exception.RequestException
import com.fun.config.HttpClientConstant
import com.fun.config.RequestType
import com.fun.frame.Save
import com.fun.utils.Time
import net.sf.json.JSONObject
import org.apache.commons.lang3.StringUtils
import org.apache.http.Header
import org.apache.http.HttpEntity
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpRequestBase
import org.apache.http.util.EntityUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory /**
* 重写FanLibrary,使用面对对象思想
*/
public class FunRequest extends FanLibrary implements Serializable, Cloneable { private static final long serialVersionUID = -4153600036943378727L; static Logger logger = LoggerFactory.getLogger(FunRequest.class) /**
* 请求类型,true为get,false为post
*/ RequestType requestType /**
* 请求对象
*/ HttpRequestBase request /**
* host地址
*/ String host = EMPTY /**
* 接口地址
*/ String apiName = EMPTY /**
* 请求地址,如果为空则由host和apiname拼接
*/ String uri = EMPTY /**
* header集合
*/ List<Header> headers = new ArrayList<>() /**
* get参数
*/ JSONObject args = new JSONObject() /**
* post参数,表单
*/ JSONObject params = new JSONObject() /**
* json参数
*/ JSONObject json = new JSONObject() /**
* 响应,若没有这个参数,从将funrequest对象转换成json对象时会自动调用getresponse方法
*/ JSONObject response = new JSONObject() /**
* 构造方法
*
* @param requestType
*/
private FunRequest(RequestType requestType) {
this.requestType = requestType
} /**
* 获取get对象
*
* @return
*/
static FunRequest isGet() {
new FunRequest(RequestType.GET)
} /**
* 获取post对象
*
* @return
*/
static FunRequest isPost() {
new FunRequest(RequestType.POST)
} /**
* 设置host
*
* @param host
* @return
*/
FunRequest setHost(String host) {
this.host = host
this
} /**
* 设置接口地址
*
* @param apiName
* @return
*/
FunRequest setApiName(String apiName) {
this.apiName = apiName
this
} /**
* 设置uri
*
* @param uri
* @return
*/
FunRequest setUri(String uri) {
this.uri = uri
this
} /**
* 添加get参数
*
* @param key
* @param value
* @return
*/
FunRequest addArgs(Object key, Object value) {
args.put(key, value)
this
} /**
* 添加post参数
*
* @param key
* @param value
* @return
*/
FunRequest addParam(Object key, Object value) {
params.put(key, value)
this
} /**
* 添加json参数
*
* @param key
* @param value
* @return
*/
FunRequest addJson(Object key, Object value) {
json.put(key, value)
this
} /**
* 添加header
*
* @param key
* @param value
* @return
*/
FunRequest addHeader(Object key, Object value) {
headers << getHeader(key.toString(), value.toString())
this
} /**
* 添加header
*
* @param header
* @return
*/
public FunRequest addHeader(Header header) {
headers.add(header)
this
} /**
* 批量添加header
*
* @param header
* @return
*/
FunRequest addHeader(List<Header> header) {
header.each {h -> headers << h}
this
} /**
* 增加header中cookies
*
* @param cookies
* @return
*/
FunRequest addCookies(JSONObject cookies) {
headers << getCookies(cookies)
this
} FunRequest setHeaders(List<Header> headers) {
this.headers.addAll(headers)
this
} FunRequest setArgs(JSONObject args) {
this.args.putAll(args)
this
} FunRequest setParams(JSONObject params) {
this.params.putAll(params)
this
} FunRequest setJson(JSONObject json) {
this.json.putAll(json)
this
} /**
* 获取请求响应,兼容相关参数方法,不包括file
*
* @return
*/
JSONObject getResponse() {
response = response.isEmpty() ? getHttpResponse(request == null ? getRequest() : request) : response
response
} /**
* 获取请求对象
*
* @return
*/
HttpRequestBase getRequest() {
if (request != null) request;
if (StringUtils.isEmpty(uri))
uri = host + apiName
switch (requestType) {
case RequestType.GET:
request = FanLibrary.getHttpGet(uri, args)
break
case RequestType.POST:
request = !params.isEmpty() ? FanLibrary.getHttpPost(uri + changeJsonToArguments(args), params) : !json.isEmpty() ? getHttpPost(uri + changeJsonToArguments(args), json.toString()) : getHttpPost(uri + changeJsonToArguments(args))
break
}
for (Header header in headers) {
request.addHeader(header)
}
logger.debug("请求信息:{}", new RequestInfo(this.request).toString())
request
} @Override
FunRequest clone() {
def fun = new FunRequest()
fun.setRequest(cloneRequest(getRequest()))
fun
} @Override
public String toString() {
return "{" +
"requestType='" + requestType.getName() + '\'' +
", host='" + host + '\'' +
", apiName='" + apiName + '\'' +
", uri='" + uri + '\'' +
", headers=" + header2Json(headers).toString() +
", args=" + args.toString() +
", params=" + params.toString() +
", json=" + json.toString() +
", response=" + getResponse().toString() +
'}';
} /**
* 从requestbase对象从初始化funrequest
* @param base
* @return
*/
static FunRequest initFromRequest(HttpRequestBase base) {
FunRequest request = null;
String method = base.getMethod();
RequestType requestType = RequestType.getRequestType(method);
String uri = base.getURI().toString();
List<Header> headers = Arrays.asList(base.getAllHeaders());
if (requestType == requestType.GET) {
request = FunRequest.isGet().setUri(uri).setHeaders(headers);
} else if (requestType == RequestType.POST || requestType == RequestType.FUN) {
HttpPost post = (HttpPost) base;
HttpEntity entity = post.getEntity();
String value = entity.getContentType().getValue();
String content = null;
try {
content = EntityUtils.toString(entity);
} catch (IOException e) {
logger.error("解析响应失败!", e)
fail();
}
if (value.equalsIgnoreCase(HttpClientConstant.ContentType_TEXT.getValue()) || value.equalsIgnoreCase(HttpClientConstant.ContentType_JSON.getValue())) {
request = FunRequest.isPost().setUri(uri).setHeaders(headers).setJson(JSONObject.fromObject(content));
} else if (value.equalsIgnoreCase(HttpClientConstant.ContentType_FORM.getValue())) {
request = FunRequest.isPost().setUri(uri).setHeaders(headers).setParams(getJson(content.split("&")));
}
} else {
RequestException.fail("不支持的请求类型!");
}
return request;
} /**
* 拷贝HttpRequestBase对象
* @param base
* @return
*/
static HttpRequestBase cloneRequest(HttpRequestBase base) {
return initFromRequest(base).getRequest()
} /**
* 保存请求和响应
* @param base
* @param response
*/
public static void save(HttpRequestBase base, JSONObject response) {
FunRequest request = initFromRequest(base)
request.setResponse(response);
Save.info("/request/" + Time.getDate().substring(8) + SPACE_1 + request.getUri().replace(OR, PART), request.toString());
} }

然后在框架是添加一个key来控制是否保存响应,然后调用保存方法:

if (SAVE_KEY) FunRequest.save(request, res);

其中,res是响应内容,已经解析为json格式,对于非json格式响应做了兼容。同事在保存路径和保存量也做配置初始化的过程中做了校验,这个太简单就不发了。

其中一个header2Json方法是为了解决保存header时候不必须信息太多的问题,内容如下:

    /**
* 将header转成json对象
*
* @param headers
* @return
*/
public static JSONObject header2Json(List<Header> headers) {
JSONObject h = new JSONObject();
headers.forEach(x -> h.put(x.getName(), x.getValue()));
return h;
}

这个是内容:

{requestType='post', host='', apiName='', uri='https://cn.bing.com/search', headers={"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"}, args={}, params={"q":"fun"}, json={}, response={"3242":"234"}}

这样做的好处就是,如果想复现某个出现问题的request,直接从文件中读取保存的request信息,借由funrequest类对象即可复现这个请求,还可以跟记录的response做对比。


  • 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。

技术类文章精选

非技术文章精选

如何保存HTTPrequestbase和CloseableHttpResponse的更多相关文章

  1. HttpClient的get+post请求使用

    啥都不说,先上代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReade ...

  2. java后台中处理图片辅助类汇总(上传图片到服务器,从服务器下载图片保存到本地,缩放图片,copy图片,往图片添加水印图片或者文字,生成二维码,删除图片等)

    最近工作中处理小程序宝箱活动,需要java画海报,所以把这块都快百度遍了,记录一下处理的方法,百度博客上面也有不少坑! 获取本地图片路径: String bgPath = Thread.current ...

  3. Spring Boot+微信小程序_保存微信登录者的个人信息

    1. 前言 微信小程序开发平台,提供有一类 API,可以让开发者获取到微信登录用户的个人数据.这类 API 统称为开放接口. Tip:微信小程序开发平台,会把微信登录用户的个人信息分为明文数据和敏感数 ...

  4. 使用Python保存屏幕截图(不使用PIL)

    起因 在极客学院讲授<使用Python编写远程控制程序>的课程中,涉及到查看被控制电脑屏幕截图的功能. 如果使用PIL,这个需求只需要三行代码: from PIL import Image ...

  5. C# 对象实例化 用json保存 泛型类 可以很方便的保存程序设置

    参考页面: http://www.yuanjiaocheng.net/webapi/test-webapi.html http://www.yuanjiaocheng.net/webapi/web-a ...

  6. C# 对象实例化 用json保存 泛型类 可以很方便的保存程序设置

    用于永久化对象,什么程序都行,依赖NewtonSoft.用于json序列化和反序列化. using Newtonsoft.Json; using System; using System.Collec ...

  7. MATLAB中绘制质点轨迹动图并保存成GIF

    工作需要在MATLAB中绘制质点轨迹并保存成GIF以便展示. 绘制质点轨迹动图可用comet和comet3命令,使用例子如下: t = 0:.01:2*pi;x = cos(2*t).*(cos(t) ...

  8. mono中发送邮件并保存本次收件人的地址

    在ios端mono开发中,发送邮件可以选择调用ios原生email程序.有两种方式实现这种功能,一是程序跳转到ipad中email程序,另外一种是将发送邮件的界面在自己应用里弹出. 首先第一种方式的代 ...

  9. mono for android 获取手机照片或拍照并裁剪保存

    axml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ...

随机推荐

  1. Spring security获取当前用户

    1.如果在jsp页面中获取可以使用spring security的标签 页面引入标签 <%@ taglib prefix="sec" uri="http://www ...

  2. oralce函数 STDDEV([distinct|all]x)

    [功能]统计数据表选中行x列的标准误差. [参数]all表示对所有的值求标准误差,distinct只对不同的值求标准误差,默认为all 如果有参数distinct或all,需有空格与x(列)隔开. [ ...

  3. MaxCompute Studio使用心得系列7——作业对比

    在数据开发过程中,我们通常需要将两个作业进行对比从而定位作业运行性能或者结果有差异的问题,但是对比作业时需要同时打开两个studio 的tab页,或者两个Logview页,不停切换进行对比,使用起来非 ...

  4. oracle 和 mysql 遍历当前月份每一天

    获取当前月份的每一天的数据 oracle SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') + (ROWNUM - 1) DAY_ID FROM ...

  5. oracle函数 current_timestamp

    [功能]:以timestamp with time zone数据类型返回当前会话时区中的当前日期 [参数]:没有参数,没有括号 [返回]:日期 [示例]select current_timestamp ...

  6. npm基础用法

    一. 安装 npm基于nodejs,因此应该先安装nodejs 可在nodejs官网中下载安装 我们一般选择安装稳定版,即长期支持版 安装过程很简单,和普通的软件一样,一直 下一步 就好了 nodej ...

  7. hdu 2410 Barbara Bennett's Wild Numbers

    Problem - 2410 挺好玩的一道题目.这道题的意思是给出一个模糊值以及一个确定值,要求求出模糊值中大于确定值的个数有多少. 这题我是直接用dfs的方法搜索的,对于每一位如果之前位置的形成的数 ...

  8. H3C 以太网集线器

  9. 5分钟了解为什么学习Go

    1.什么是Go语言? Google开源 编译型语言 21世纪的C语言(主流编程语言都是单线程环境下发布的) 2.Go语言的特点? 简单易学习(类似python学习难度,自带格式化) 开发效率高 执行性 ...

  10. Python--day19--collections模块

    常用模块一的各个模块解释: 文件名不要起跟模块名一样:(模块本身就是一个py文件) collection模块: namedtuple方法: 例1: 例2: dequeue方法:双端队列 有序字典Ord ...