Automating Complex API Tests with Groovy: A Modular Script Framework
This article presents a Groovy‑based modular framework for automating complex, interrelated API tests, detailing how to structure test modules, manage user credentials and tokens, and execute concurrent requests using custom thread handling, with full source code examples for the main driver, UserCenter, and base classes.
Overview
This article describes a Groovy‑based framework for testing multi‑step API workflows. It builds on existing Java testing libraries and uses script‑driven execution to simulate realistic user interactions such as login, token handling, and password modification.
Architecture
The framework is organized around three core classes:
OkayBase – provides common utilities (logging, user identity fields, token handling, request parameter construction, password encryption, and a generic isRight(JSONObject) method that validates the response meta code and data presence).
UserCenter – extends OkayBase and implements the password‑change API call. It builds the request parameters, encrypts the passwords with RSAUtils.getPassword(), sends a POST request, logs the response, and updates the stored token when the call succeeds.
T8 – the entry point that creates a configurable thread pool to execute the modifyPwd() operation concurrently.
Core Workflow
The password‑change scenario follows these steps:
Login using the User object's uname and pwd to obtain an initial token.
Call the modify‑pwd endpoint with three parameters: newpwd, oldpwd, and the current token.
If the response is successful, extract the new token from response.data.token and store it for subsequent requests.
Threaded Execution (class T8 )
The main method expects two command‑line arguments: args[0] – number of concurrent threads. args[1] – number of requests each thread should perform.
For each thread the following actions are performed:
Obtain a base instance via getBase(i) (provides user credentials).
Instantiate UserCenter with the base.
Execute a warm‑up call userCenter.modifyPwd().
Create an anonymous subclass of ThreadBase that overrides doing() to repeatedly invoke userCenter.modifyPwd().
Set the repeat count with threadBase.setTimes(times) and add the thread to a list.
After all thread objects are prepared, a Concurrent runner starts them in parallel, and allOver() is called to clean up resources.
class T8 extends OkayBase {
public static void main(String[] args) {
int thread = changeStringToInt(args[0]);
int times = changeStringToInt(args[1]);
List<ThreadBase> threads = new ArrayList<>();
for (int i = 0; i < thread; i++) {
OkayBase base = getBase(i);
UserCenter userCenter = new UserCenter(base);
userCenter.modifyPwd(); // warm‑up
ThreadBase threadBase = new ThreadBase() {
@Override
protected void before() {}
@Override
protected void doing() throws Exception {
userCenter.modifyPwd();
}
@Override
protected void after() {}
};
threadBase.setTimes(times);
threads.add(threadBase);
}
new Concurrent(threads).start();
allOver();
}
}Implementation of UserCenter
public class UserCenter extends OkayBase {
private static Logger logger = LoggerFactory.getLogger(UserCenter.class);
public UserCenter(OkayBase okayBase) {
super(okayBase);
}
public JSONObject modifyPwd() {
String url = UserApi.MODIFY_PWD;
JSONObject params = getParams();
params.put("newpwd", getPassword(this.getUname()));
params.put("oldpwd", getPassword(this.getPwd()));
JSONObject response = getPostResponse(url, params);
output(response);
if (isRight(response)) {
String token = response.getJSONObject("data").getString("token");
this.setToken(token);
}
return response;
}
}Implementation of OkayBase
public class OkayBase extends SourceCode implements IBase {
private static Logger logger = LoggerFactory.getLogger(OkayBase.class);
int uid;
String token;
String uname;
String pwd;
public OkayBase(String uname, String pwd) {
this.uname = uname;
this.pwd = pwd;
login();
}
public String getPassword() {
String s = uname.substring(uname.length() - 6);
return getPassword(s);
}
public String getPassword(String pwd) {
return RSAUtils.getPassword(pwd);
}
public JSONObject getParams() {
JSONObject json = getJson("uid=" + uid, "token=" + token);
json.put("imei", "isFake");
json.put("serial", "W170500652");
json.put("ua", "f_an_4..0");
return json;
}
@Override
public boolean isRight(JSONObject jsonObject) {
int code = TEST_ERROR_CODE;
try {
code = jsonObject.getJSONObject("meta").getInt("ecode");
JSONObject data = jsonObject.getJSONObject("data");
return code == 0 && !data.isEmpty();
} catch (Exception e) {
return false;
}
}
/** Test cleanup */
public static void allOver() {
FanLibrary.testOver();
}
}Key Points
State is carried between modules via a shared User object (username, password, token, etc.).
Passwords are encrypted on the client side using RSAUtils.getPassword() before being sent.
The framework’s modular design allows easy addition of new API groups while reusing common utilities from OkayBase.
Configurable thread count and request repetitions enable performance testing, regression verification, and complex scenario automation.
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.
