Operations 13 min read

Mastering FunTester: Distributed Performance Testing API and Multi‑Language Samples

This article introduces the FunTester distributed testing framework, explains its single‑node HTTP API, provides complete Java, generic Java, and Groovy code examples, details request parameters, response structure, and the underlying PerformanceResultBean class for analyzing test results.

FunTester
FunTester
FunTester
Mastering FunTester: Distributed Performance Testing API and Multi‑Language Samples

Distributed testing API

The FunTester framework provides a single‑node distributed testing service that accepts test tasks via an HTTP POST interface. The service is intended for local deployment and can be accessed at: http://124.70.188.11:8080/test/post Request method: POST with application/json payload.

Request parameters

times

(int) – total number of requests to execute. thread (int) – number of concurrent threads. mode (String) – test mode, default ftt. desc (String) – description of the test case. runup (int) – soft‑start time (seconds). key (String) – access key provided by the framework maintainer. request (Object) – definition of the HTTP request to be tested.

Request object for non‑Java languages

requestType

(String) – GET or POST. uri (String) – target URL, e.g. http://your-target-url. args (JSON) – query parameters for GET. json (JSON) – JSON body for POST. params (JSON) – form‑encoded parameters for POST. headers (JSON array) – list of key:value header objects.

Example payload

{
    "mode":"ftt",
    "request":{
        "requestType":"GET",
        "uri":"http://your-target-url",
        "args":{},
        "json":{},
        "params":{},
        "headers":[]
    },
    "times":10,
    "thread":1,
    "runup":1,
    "key":"funtester2021",
    "desc":"FunTester distributed test demo"
}
Postman request screenshot
Postman request screenshot

Java client implementation (FunTester based)

The Java client uses com.funtester.httpclient.FunRequest. The source code is hosted on Gitee: https://gitee.com/fanapi/tester (branch oker).

import com.alibaba.fastjson.JSONObject;
import com.funtester.httpclient.ClientManage;
import com.funtester.httpclient.FunLibrary;
import com.funtester.httpclient.FunRequest;
import com.funtester.utils.DecodeEncode;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;

public class PerSerTest extends FunLibrary {
    public static void main(String[] args) {
        ClientManage.init(100, 100, 0, EMPTY, 0);
        JSONObject res = new JSONObject();
        res.put("times", 100);
        res.put("thread", 10);
        res.put("key", "");
        res.put("mode", "ftt");
        res.put("desc", "FunTester distributed test Demo");
        res.put("runup", 10);
        String url = "http://your-target-url";
        HttpGet get = FunLibrary.getHttpGet(url);
        FunRequest request = FunRequest.initFromRequest(get);
        res.put("request", request.toJson());
        HttpPost httpPost = getHttpPost("http://124.70.188.11:8080/test/post", res.toString());
        JSONObject response = getHttpResponse(httpPost);
        output(response);
        String table = response.getJSONObject("data").getString("table");
        output(DecodeEncode.unzipBase64(table));
    }
}

Generic JSON‑based Java version

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.funtester.httpclient.ClientManage;
import com.funtester.httpclient.FunLibrary;
import com.funtester.utils.DecodeEncode;
import org.apache.http.client.methods.HttpPost;

public class PerSerTest2 extends FunLibrary {
    public static void main(String[] args) {
        ClientManage.init(100, 100, 0, EMPTY, 0);
        JSONObject res = new JSONObject();
        res.put("times", 10);
        res.put("thread", 10);
        res.put("key", "");
        res.put("mode", "ftt");
        res.put("desc", "FunTester distributed test Demo");
        res.put("runup", 10);
        JSONObject req = new JSONObject();
        req.put("requestType", "GET");
        req.put("uri", "http://your-target-url");
        req.put("args", new JSONObject());
        req.put("json", new JSONObject());
        req.put("params", new JSONObject());
        req.put("headers", new JSONArray());
        res.put("request", req);
        HttpPost httpPost = getHttpPost("http://124.70.188.11:8080/test/post", res.toString());
        JSONObject response = getHttpResponse(httpPost);
        output(response);
        String table = response.getJSONObject("data").getString("table");
        output(DecodeEncode.unzipBase64(table));
    }
}

Groovy version (concise syntax)

import com.alibaba.fastjson.JSONObject
import com.funtester.httpclient.ClientManage
import com.funtester.httpclient.FunLibrary
import com.funtester.httpclient.FunRequest

class PerSerTest extends FunLibrary {
    static void main(String[] args) {
        ClientManage.init(100,100,0,EMPTY,0)
        def res = new JSONObject()
        res.times = 100
        res.thread = 10
        res.key = ""
        res.mode = "ftt"
        res.desc = "FunTester distributed test Demo"
        res.runup = 10
        String url = "http://your-target-url"
        def get = FunLibrary.getHttpGet(url)
        def request = FunRequest.initFromRequest(get)
        res.request = request.toJson()
        def post = getHttpPost("http://124.70.188.11:8080/test/post", res.toString())
        def response = getHttpResponse(post)
        output(response)
        String table = response.getJSONObject("data").getString("table")
        output(DecodeEncode.unzipBase64(table))
    }
}

Response structure

The API returns a JSON object whose data field contains a com.funtester.base.bean.PerformanceResultBean instance. Key fields: code – status code (0 indicates success). rt – average response time (ms). qps – calculated throughput (threads / avg time). qps2 – throughput derived from count / duration (used in fixed‑QPS mode). threads, total, executeTotal – concurrency and request counts. errorRate, failRate – quality metrics. table – Base64‑encoded performance table; decode with DecodeEncode.unzipBase64.

Example response excerpt:

{
  "code":0,
  "data":{
    "rt":18,
    "failRate":0.0,
    "threads":10,
    "deviation":"53.29%",
    "qps2":259.4752186588921,
    "errorRate":0.0,
    "executeTotal":801,
    "total":1801,
    "qps":555.5555555555555,
    "startTime":"2021-06-01 18:09:17",
    "endTime":"2021-06-01 18:09:20",
    "mark":"FunTester distributed test Demo",
    "table":"eJzj5VIgCNxK..."
  },
  "FunTester":200
}

To view the performance table:

String table = response.getJSONObject("data").getString("table");
output(DecodeEncode.unzipBase64(table));
Graphical test data
Graphical test data

PerformanceResultBean class

package com.funtester.base.bean;

import com.funtester.db.mysql.MySqlTest;
import com.funtester.frame.Output;
import com.funtester.utils.DecodeEncode;

/** Performance test result bean */
public class PerformanceResultBean extends AbstractBean implements java.io.Serializable {
    private static final long serialVersionUID = -1595942562342357L;

    String mark;            // test case description
    String startTime;       // start timestamp
    String endTime;         // end timestamp
    String table;           // Base64‑encoded table data
    int threads;            // number of threads
    int total;              // total request count
    int rt;                 // average response time (ms)
    double qps;            // throughput (threads / avg time)
    double qps2;           // throughput from count/duration
    String deviation;       // percentage deviation between qps and qps2
    double errorRate;      // error rate
    double failRate;       // failure rate
    int executeTotal;      // total executed requests

    public PerformanceResultBean(String mark, String startTime, String endTime,
                                 int threads, int total, int rt,
                                 double qps, double qps2,
                                 double errorRate, double failRate,
                                 int executeTotal, String table) {
        this.mark = mark;
        this.startTime = startTime;
        this.endTime = endTime;
        this.threads = threads;
        this.total = total;
        this.rt = rt;
        this.qps = qps;
        this.qps2 = qps2;
        this.errorRate = errorRate;
        this.failRate = failRate;
        this.executeTotal = executeTotal;
        this.table = DecodeEncode.zipBase64(table);
        this.deviation = com.funtester.frame.SourceCode.getPercent(
                Math.abs(qps - qps2) * 100 / Math.max(qps, qps2));
        Output.output(this.toJson());
        Output.output(table);
        MySqlTest.savePerformanceBean(this);
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaPerformance TestingDistributed TestingAPIGroovyFunTester
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.