Script‑Based Performance Testing Scenarios Using the FunTester Framework
This article introduces a flexible, script‑driven performance testing approach built on the FunTester framework, explains how to write Groovy/Java test scripts, demonstrates a demo implementation with reflection‑based execution, and covers test case creation, transmission, and execution for HTTP‑based load testing.
The author revisits two previous performance‑testing solutions and presents a third, script‑based approach that runs test cases directly as Groovy or Java scripts on a performance‑testing service, eliminating the need to package test cases into JAR files.
Using the FunTester framework, scripts can be uploaded to the server (or stored in a database or Git) and executed without complex file management. This method supports HTTP protocol testing for single‑link, multi‑link, and full‑link scenarios, and can be extended to other protocols such as Dubbo, Socket, Redis, and MySQL.
Demo Implementation
A sample test class named Share demonstrates reflection‑based execution of four method types (no‑arg, primitive parameter, String object, and String array). The class relies on com.funtester.frame.execute.ExecuteSource to invoke methods inside a JAR package.
import com.funtester.config.Constant
import com.funtester.frame.execute.Concurrent
import com.funtester.frame.thread.RequestThreadTimes
import com.funtester.httpclient.ClientManage
import com.funtester.httpclient.FunLibrary
import com.funtester.utils.ArgsUtil
import org.apache.http.client.methods.HttpGet
class Share extends FunLibrary {
public static void main(String[] args) {
ClientManage.init(10, 5, 0, EMPTY, 0);
def util = new ArgsUtil(args)
int thread = util.getIntOrdefault(0, 20);
int times = util.getIntOrdefault(1, 100);
String url = "http://localhost:12345/m";
HttpGet get = getHttpGet(url);
Constant.RUNUP_TIME = 0;
RequestThreadTimes task = new RequestThreadTimes(get, times);
new Concurrent(task, thread, "本地固定QPS测试").start();
testOver();
}
}The execution method reads the script file and runs it via ExecuteGroovy.executeScript :
String s = RWUtil.readTxtByString("/Users/oker/IdeaProjects/funtester/src/test/groovy/com/funtest/groovytest/Share.groovy");
ExecuteGroovy.executeScript(s);To enable parameterization, a wrapper method test(String params) splits a comma‑separated string and forwards the arguments to main :
public static void test(String params) {
main(params.split(COMMA))
}Running the parameterized method looks like:
ExecuteGroovy.executeFileMethod("/Users/oker/IdeaProjects/funtester/src/test/groovy/com/funtest/groovytest/Share.groovy", "test", "20,100");Test Case Creation
A Groovy script named Login_collect_uncollect shows a single‑link test case that uses various utility classes to perform login, query, collect, and un‑collect actions. The script defines an inner class K to hold ID, type, and level information.
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()
}
private static class FunTester extends ThreadLimitTimesCount
{
// implementation omitted for brevity
}
private static class K extends AbstractBean {
int id
int type
int level
K(int id, int type, int level) { this.id=id; this.type=type; this.level=level }
}
}Test Case Transmission
Test cases are treated as simple String objects; they can be uploaded, saved, or edited by storing the script text in a database or Git repository.
Test Execution
The ExecuteSource class provides reflective utilities to invoke arbitrary methods based on a string path and parameter list. It handles parameter type conversion (e.g., Integer, JSON) and logs any reflection errors.
package com.funtester.frame.execute;
import com.alibaba.fastjson.JSON;
import com.funtester.base.exception.FailException;
import com.funtester.frame.SourceCode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class ExecuteSource extends SourceCode {
private static Logger logger = LogManager.getLogger(ExecuteSource.class);
public static Object executeMethod(List
params) {
Object[] objects = params.subList(1, params.size()).toArray();
return executeMethod(params.get(0), objects);
}
public static Object executeMethod(String[] params) {
return executeMethod(Arrays.asList(params));
}
public static Object executeMethod(String path, Object... paramsTpey) {
// reflection logic omitted for brevity
return null;
}
}The article concludes with links to the FunTester repository and other related technical articles.
FunTester
10k followers, 1k articles | completely useless
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.