How to Diversify Request Parameters for Robust Performance Testing
This article explains practical techniques for generating varied request parameters—such as random numbers, thread‑safe identifiers, random strings, and upstream data extraction—to avoid identical inputs in multi‑call performance tests and improve test reliability.
Background
When testing a single‑link performance scenario, the same API may be called multiple times with identical parameters, which limits the test's ability to uncover issues because only one of the responses is actually used for subsequent steps.
Business‑Unrelated Parameters
Random Numbers
A simple utility method generates a random integer between 1 and num (inclusive):
public static int getRandomInt(int num) {
return random.get().nextInt(num) + 1;
}
public static int getRandomIntRange(int start, int end) {
if (end <= start) return TEST_ERROR_CODE;
return random.get().nextInt(end - start) + start;
}Thread‑Safe Random Values
To obtain unique values per thread, a static AtomicInteger is used as a base, combined with a per‑thread counter:
public class ParamMark extends SourceCode implements MarkThread, Cloneable, Serializable {
private static final long serialVersionUID = -5532592151245141262L;
public static AtomicInteger threadName = new AtomicInteger(getRandomIntRange(1000, 9000));
String name;
int num = getRandomIntRange(100, 999) * 1000;
@Override
public String mark(ThreadBase threadBase) {
return name + num++;
}
@Override
public ParamMark clone() {
return new ParamMark();
}
public ParamMark() {
this.name = threadName.getAndIncrement() + EMPTY;
}
public ParamMark(String name) {
this();
this.name = name;
}
}The combination of threadName and num guarantees globally unique identifiers without relying on timestamps.
Random Strings
Utility methods generate fixed‑length random strings, either with or without digits:
static String getString(int length) {
StringBuffer sb = new StringBuffer();
if (length < 1) return sb.toString();
for (int i = 1; i <= length; i++) {
sb.append(getChar());
}
return sb.toString();
}
static String getStringWithoutNum(int length) {
StringBuffer sb = new StringBuffer();
if (length < 1) return sb.toString();
for (int i = 1; i <= length; i++) {
sb.append(getWord());
}
return sb.toString();
}
public static long getNanoMark() {
return System.nanoTime();
}When stricter uniqueness is required, nanosecond timestamps can be used.
Business‑Related Parameters
Random Values Within a Range
For parameters that must fall within a specific numeric range (e.g., 0‑7), random selection is applied:
public static <F extends Number> F random(F... fs) {
return fs[getRandomInt(fs.length) - 1];
}
public static String random(String... fs) {
if (ArrayUtils.isEmpty(fs)) ParamException.fail("Array cannot be empty!");
return fs[getRandomInt(fs.length) - 1];
}
public static <F extends Object> F random(List<F> list) {
if (list == null || list.isEmpty()) ParamException.fail("Array cannot be empty!");
return list.get(getRandomInt(list.size()) - 1);
}Groovy scripts can use the range syntax 0..10 for similar effect.
Upstream Interface Data
Objects required for the test can be fetched from an upstream API, parsed, and stored in a List<K> for later random selection:
def klist = mirro.getKList();
List<K> kss = new ArrayList<>();
for (Object item : klist.getJSONArray("data")) {
JSONObject parse = JSON.parse(JSON.toJSONString(item));
int level = parse.getIntValue("node_level");
int type = parse.getIntValue("ktype");
int id = parse.getIntValue("id");
kss.add(new K(id, type, level));
}
K ks = kss.get(0);
K ks2 = kss.get(1);
K ks3 = kss.get(3);
clazz.recommend(ks3.id, ks3.type, ks3.level);
clazz.recommend(ks2.id, ks2.type, ks2.level);
JSONObject response = clazz.recommend(ks.id, ks.type, ks.level);Pre‑Creating Data for Multi‑Threaded Tests
A LinkedBlockingQueue<String> holds prepared SQL statements or other payloads, ensuring each thread retrieves a unique item:
static LinkedBlockingQueue<String> sqls = new LinkedBlockingQueue<>();
public static boolean addWork(String sql) {
try {
sqls.put(sql);
} catch (InterruptedException e) {
logger.warn("Failed to add DB task!", e);
return false;
}
return true;
}
static String getWork() {
String sql = null;
try {
sql = sqls.poll(SqlConstant.MYSQLWORK_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
logger.warn("Failed to get DB task!", e);
} finally {
return sql;
}
}Estimating the required volume beforehand prevents test failures due to insufficient data; alternatively, a dedicated thread can continuously feed the queue.
Conclusion
By incorporating random numbers, thread‑safe identifiers, random strings, upstream data extraction, and pre‑created data pools, testers can significantly increase the diversity of request parameters in performance testing, reducing false positives and better simulating real‑world usage patterns.
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.
