在最近的工作中,挫败感极大,我做了深刻反思,得出来一个道理:如是观照,实事求是。
原因比较复杂,其中一项是因为某一批接口测试需求比较紧,我之前一直的思路就是尽可能模拟真实数据,使用多用户进行性能测试,一般测试前都需要尽量大量的数据准备工作。但是这次不灵了,接口之间的参数依赖过于复杂,如果真写起来,可真就是把端上的工作重新做一遍,不值当的。
所以我取了个巧,在模拟用户造数据的时候,我直接复制了浏览器里面的接口请求,然后通过不断的刷这个接口去造数据,就不用去一个参数一个参数的写请求了。顺便还能给端上同学写一个简单的性能测试工具Demo,方便他们做一些简单的性能测试。
首先我去解析GET
和POST
请求,然后通过工具类FunRequest
生成一个HttpRequestBase
,然后验证一下请求,就可以正常进行性能测试阶段了。
这里我采用了复制curl
的格式的方式,因为其他的方式数据量太大了,比较复杂,解析起来困难,容易出BUG
。
分享一下复制的结果,删除了域名。
curl 'https://j****.cn/home/course_list?_=1611648498164&custom_directory_id=4630377&origin=0&page=1&page_size=10' \
-H 'Connection: keep-alive' \
-H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' \
-H 'DNT: 1' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36' \
-H 'requestid: 010427916771' \
-H 'Accept: application/json, text/javascript, */*; q=0.01' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'is_new_okay: 1' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Referer: https://jiaoshi-dev.xk12.cn/' \
-H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8' \
-H 'Cookie: db_log=1; org_id=640; user_action_cookie=user_action_87cf9c4d-1e22-4c8c-982e-a4419fa6dc1b_62951571858; teacher_id=9fec845f498a47abb68426c14f90693e' \
--compressed
分享一下复制的结果,删除了域名,too!
curl 'https://j****.cn/myResourcePool/deleteResource' \
-H 'Connection: keep-alive' \
-H 'sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"' \
-H 'DNT: 1' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36' \
-H 'requestid: 011342477158' \
-H 'Accept: application/json, text/javascript, */*; q=0.01' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'is_new_okay: 1' \
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
-H 'Origin: https://jiaoshi-dev.xk12.cn' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Referer: https://jiaoshi-dev.xk12.cn/myResourcePool_vm/my_resources' \
-H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8' \
-H 'Cookie: db_log=1; org_id=640; user_action_cookie=user_action_87cf9c4d-1e22-4c8c-982e-a4419fa6dc1b_62951571858; teacher_id=9fec845f498a47abb68426c14f90693e' \
--data-raw 'res_id=2317045&res_type=3' \
--compressed
这里我是把复制的请求写到本地的一个文本文件中,首先读取,然后遍历处理。
public static HttpRequestBase getRequest(String path) {
def fileinfo = WriteRead.readTxtFileByLine(LONG_Path + path).stream().map {it.trim()}
def base = new CurlRequestBase()
fileinfo.each {
if (it.startsWith("curl")) {
def split = it.split(" ", 2)
def type = split[0]
def value = split[1]
base.url = value.substring(value.indexOf('h'), value.lastIndexOf("'"))
} else if (it.startsWith("-H")) {
def split = it.split(" ", 2)[1].split(": ")
base.headers << getHeader(split[0].substring(1), split[1].substring(0, split[1].lastIndexOf("'")))
} else if (it.startsWith("--data-raw")) {
base.params = getJson(it.substring(it.indexOf("'") + 1, it.lastIndexOf("'")).split("&"))
base.type = RequestType.POST
}
}
base.type == RequestType.GET ? FunRequest.isGet().setUri(base.url).addHeader(base.headers).getRequest() : FunRequest.isPost().setUri(base.url).addHeader(base.headers).addParams(base.params).getRequest()
}
中间用到了一个CurlRequestBase
内部静态类。
static class CurlRequestBase {
String url
RequestType type =RequestType.GET
List<Header> headers = new ArrayList<>()
JSONObject params = new JSONObject()
}
这个比较容易,接入之前的性能测试框架即可。
public static void main(String[] args) {
def request = getRequest("get")
output FanLibrary.getHttpResponse(request)
def thread = new RequestThreadTimes<HttpRequestBase>(request, 100)
new Concurrent(thread,30,"FunTester get请求测试").start()
testOver()
}
响应的数据量有点大,这里就不放响应结果了,直接放性能测试结果。
INFO-> gc回收线程开始了!
INFO-> 线程:FunTester get请求测试16,执行次数:100,错误次数: 0,总耗时:12.92 s
······省略········
INFO-> 线程:FunTester get请求测试19,执行次数:100,错误次数: 0,总耗时:14.017 s
INFO-> 总计30个线程,共用时:14.033 s,执行总数:3000,错误数:0,失败数:0
INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/fun/long/data/FunTester get请求测试2021012617384730
INFO->
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
> {
> ① . "rt":132,
> ① . "total":3000,
> ① . "qps":225.86109542631283,
> ① . "failRate":0.0,
> ① . "threads":30,
> ① . "startTime":"2021-01-26 17:38:47",
> ① . "endTime":"2021-01-26 17:39:01",
> ① . "errorRate":0.0,
> ① . "executeTotal":3000,
> ① . "mark":"FunTester get请求测试20210126173847",
> ① . "table":"\r\n\t\t\t\tFunTester get请求测试30·····省略,见下图····\r\n"
> }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
INFO->
FunTester get请求测试30
>>响应时间分布图,横轴排序分成桶的序号,纵轴每个桶的中位数<<
--<中位数数据最小值为:93 ms,最大值:204 ms>--
██
██
██
▅▅ ██
▃▃ ██ ██
▃▃ ██ ██ ██
▂▂ ▇▇ ██ ██ ██ ██
▁▁ ▄▄ ▇▇ ██ ██ ██ ██ ██ ██
▂▂ ▅▅ ▇▇ ██ ██ ██ ██ ██ ██ ██ ██ ██
▁▁ ▄▄ ▅▅ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
▃▃ ▅▅ ▇▇ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
▂▂ ▅▅ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
▃▃ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
INFO-> gc回收线程结束了!
Process finished with exit code 0
最后的响应结果需要使用等宽字体查看才行,如果系统默认的字是非等宽的,请参照下图:
关于如何使用性能测试框架和生成性能测试结果,有兴趣的可以翻一翻以前的文章。