在之前的文章性能测试中标记每个请求、链路压测中如何记录每一个耗时的请求中,我详细说明了如何标记HTTPrequestbase
对象和记录HTTPrequestbase
请求的响应时间,都是通过header
中的某一个字段值进行标记的。
但是在实际工作中,很多时候无法进行header
标记每一个请求对象,因为服务很可能不会通过header
里面的某个字段来区分每一个请求,而且在链路压测中根本不会是一个HTTP
请求,而是好几个HTTP
请求,无法使用同一MarkRequest
进行标记,所以在通用功能无法满足需求的时候就需要我们自己进行脚本的编写,下面分享一下我在一次性能测试中,对请求参数进行标记的实践。
接口
这是一个搜索接口,通过输入keyword
来获取相关资源,具体业务和搜索能力细节这里就不讲了。下面看一下接口文档:
/**
* 首页智课搜索
*
* @param keyword
* @return
*/
public JSONObject ailearnSearch(String keyword) {
String url = LaunchApi.AILEARN_SEARCH;
JSONObject params = getParams();
params.put("keyword", keyword);
params.put("orgIdArray", Arrays.asList(80, 54, 640, 3018, 3346, 3308, 3305));
params.put("page", 1);
params.put("pageSize", 10);
params.put("stageId", 2);//1:小学,2:初中,3:高中
JSONObject response = getPostResponse(url, params);
output(response);
return response;
}
这个既是接口文档也是接口用例的基本方法,基本上是可以理解该接口的请求所需的必要因素的,相比各种各样平台或者形式提供的接口文档,我更愿意提供一个可直接请求的Demo
,当然除了业务细节内容以外。
方法改造
首先这个功能测试方法是不适应性能测试的,首先我们看getParams()
代码:
public JSONObject getParams() {
return getJson("mark=" + Common.getRequestIdHeader().getValue());
}
这里很简单的,我向参数中添加一个key
为mark
(公参)的字段,且赋上一个唯一的值,然后添加到参数里面。
但是在性能测试中,再从每一个请求里面解析这个参数比较麻烦,所以我进行了方法的改造,如何:
/**
* 首页智课搜索(用于压测)
*
* @param rid
* @return
*/
public JSONObject ailearnSearchP(String mark) {
String url = LaunchApi.AILEARN_SEARCH;
JSONObject params = new JSONObject();
params.put("mark", mark);
params.put("keyword", rstring.get(t.getAndIncrement() % rstring.size()));
params.put("orgIdArray", Arrays.asList(80, 54, 640, 3018, 3346, 3308, 3305));
params.put("page", 1);
params.put("pageSize", 10);
params.put("stageId", 2);//1:小学,2:初中,3:高中
JSONObject response = getPostResponse(url, params);
output(response);
return response;
}
我用一个参数来给公参mark
赋值,方便性能测试中调用这个方法。
性能脚本实现
这里我依然采用了内部静态类的方式完成自定义的性能多线程对象的实现,重写doing()
方法。代码如下:
package com.okayqa.elasticsearch.performance
import com.fun.base.constaint.ThreadLimitTimesCount
import com.fun.frame.execute.Concurrent
import com.fun.frame.httpclient.ClientManage
import com.fun.utils.ArgsUtil
import com.fun.utils.RString
import com.okayqa.elasticsearch.base.OkayBase
import com.okayqa.elasticsearch.function.Launch
import java.util.concurrent.atomic.AtomicInteger
public class LaunchSearch extends OkayBase {
static AtomicInteger count = new AtomicInteger(getRandomIntRange(100, 999) * 1000000)
public static void main(String[] args) {
ClientManage.init(5, 3, -1, EMPTY, 0)
def util = new ArgsUtil(args)
def thread = util.getIntOrdefault(0, 20)
int times = util.getIntOrdefault(1, 30)
def launch = new Launch()
def threads = []
thread.times {
threads << new FUN(times)
}
new Concurrent(threads, "首页智课搜索").start()
allOver()
}
static class FUN extends ThreadLimitTimesCount {
Launch drive = new Launch()
FUN(int times) {
super(null, times, null)
}
@Override
protected void doing() throws Exception {
this.threadmark = count.getAndIncrement() + RString.getString(4)
drive.ailearnSearchP(threadmark)
}
}
}
我依然使用了AtomicInteger
这个线程安全类,随机一个较大的int
数值,然后随机mark
的值的时候再添加length
为 4 的字符串,主要是为了防止多次请求重复的问题。