How to Build a Real‑World API Load Test for a Knowledge‑Base Service
This article walks through the design, scenario planning, and Java implementation of a fixed‑thread load test that simulates teacher login, knowledge‑point queries, course recommendations, and collect/uncollect actions, then presents the resulting performance metrics.
About the "Link" Concept
The term "link" is used instead of "path" to describe a sequence of UI‑driven operations that differ from pure interface testing; it serves as a reference model based on UI and product‑thinking documentation.
Collaboration Requirements
Front‑end testers need to supplement business details, while operations staff provide request‑volume ratios, which were initially estimated intuitively.
Scenario and Test Design
The test simulates a teacher logging in, retrieving a knowledge‑point list, filtering recommended courses, performing collect and un‑collect actions, and finally fetching the teacher's own course list (including originals and collections).
A fixed‑thread model is used, targeting roughly 200 concurrent threads with a backup pool of 600 virtual users; each thread represents one user and repeatedly executes a "Q" cycle.
One Q cycle consists of nine HTTP requests (no socket calls), including three modification operations and six query operations.
Implementation Details
The core logic is implemented in a static helper class and a supplementary K class that stores knowledge‑point attributes (id, type, level) for easy reuse. All API calls use primitive types and String parameters.
package com.okayqa.composer.performance.resource1_4;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.funtester.base.bean.AbstractBean;
import com.funtester.base.constaint.ThreadLimitTimesCount;
import com.funtester.frame.execute.Concurrent;
import com.funtester.httpclient.ClientManage;
import com.funtester.utils.ArgsUtil;
import com.okayqa.composer.base.OkayBase;
import com.okayqa.composer.function.Mirro;
import com.okayqa.composer.function.OKClass;
class Login_collect_uncollect extends OkayBase {
public static void main(String[] args) {
ClientManage.init(10, 5, 0, "", 0);
def util = new ArgsUtil(args);
def thread = util.getIntOrdefault(0, 30);
def times = util.getIntOrdefault(1, 40);
def tasks = [];
thread.times { tasks << new FunTester(it, times) }
new Concurrent(tasks, "资源库1.4登录>查询>收藏>取消收藏链路压测").start();
allOver();
}
// ... (inner classes FunTester and K omitted for brevity)
}The supporting AbstractBean class provides JSON conversion, file saving, console printing, and cloning utilities for bean objects.
package com.funtester.base.bean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.funtester.frame.Save;
import com.funtester.frame.SourceCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
abstract class AbstractBean {
static final Logger logger = LoggerFactory.getLogger(AbstractBean.class);
JSONObject toJson() { return JSONObject.parseObject(JSONObject.toJSONString(this)); }
def save() { Save.saveJson(this.toJson(), this.getClass().toString() + SourceCode.getMark()); }
def print() { logger.warn(this.getClass().toString() + ":" + this.toString()); }
def initFrom(String str) { JSONObject.parseObject(str, this.getClass()); }
def initFrom(Object obj) { initFrom(JSON.toJSONString(obj)); }
def copyFrom(AbstractBean source) { BeanUtils.copyProperties(source, this); }
def copyTo(AbstractBean target) { BeanUtils.copyProperties(this, target); }
@Override String toString() { return JSONObject.toJSONString(this); }
@Override protected Object clone() { initFrom(this); }
}Test Results
{
"rt":1665,
"total":1188,
"qps":18.018,
"failRate":0.0,
"threads":30,
"startTime":"2021-02-24 16:57:23",
"endTime":"2021-02-24 16:58:34",
"errorRate":1.01,
"executeTotal":1188,
"mark":"资源库1.4登录>查询>收藏>取消收藏链路压测241657",
"table":"eJzj5VLAD15sbXm2a8LTXZMN9Uyez9z9dO9Uu2fzl75Yv8ju2ZRtL6b32z3tn/..."
}The JSON output shows a response time of 1665 ms, 30 threads, a QPS of 18.018, and an error rate of 1.01 % for 1,188 total requests.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
