Mastering API Test Automation: Inside a Java Base Class for FunTester
This article presents a detailed walkthrough of a Java base class used in the FunTester API testing framework, covering static factory methods, login handling with RSA encryption, request construction, header management, response validation, and includes the full source code for reference.
Believe in the theory of ten thousand lines of code!
The post shares a practical implementation of a base class ( OkayBase) that underpins the FunTester API testing framework. It demonstrates how to encapsulate common testing functionalities such as password encryption, response structure validation, and provides static factory methods for obtaining singleton or new instances of the base class.
Gitee Repository
https://gitee.com/fanapi/tester
Source Code
package com.okayqa.studentapd.base;
import com.fun.base.bean.BeanUtil;
import com.fun.base.bean.RequestInfo;
import com.fun.base.interfaces.IBase;
import com.fun.config.HttpClientConstant;
import com.fun.config.SqlConstant;
import com.fun.config.SysInit;
import com.fun.frame.SourceCode;
import com.fun.frame.httpclient.FanLibrary;
import com.okayqa.common.Common;
import com.okayqa.common.RSAUtils;
import com.okayqa.common.Users;
import com.okayqa.studentapd.bean.UserInfoBean;
import com.okayqa.studentapd.profile.Profile;
import com.okayqa.studentapd.profile.UserApi;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
/**
* qa项目base类
*/
public class OkayBase extends SourceCode implements IBase {
private static Logger logger = LoggerFactory.getLogger(OkayBase.class);
private static OkayBase base;
static {
SqlConstant.REQUEST_TABLE = Common.SQL_REQUEST;
SqlConstant.flag = Common.SQL_KEY;
SqlConstant.PERFORMANCE_TABLE = Common.SQL_PERFORMANCE;
if (FanLibrary.getiBase() == null) FanLibrary.setiBase(new OkayBase());
}
public static String HOST = Profile.HOST;
private void getPublicKey() {
JSONObject response = getPostResponse(Profile.PUBLICK_KEY_API, getParams());
if (isRight(response)) {
logger.info("public_key:{}", response.getJSONObject("data").getString("key"));
}
}
/** Login response */
JSONObject loginResponse;
UserInfoBean userInfoBean = new UserInfoBean();
/**
* Get base object (singleton)
*/
public static OkayBase getBase() {
if (base == null) base = new OkayBase(0);
return base;
}
public static OkayBase getBase(int i) {
return new OkayBase(i);
}
protected int uid;
protected String token;
protected String uname;
protected String pwd;
protected JSONObject cookies = new JSONObject();
@Override
public void login() {
String url = UserApi.LOGIN;
JSONObject params = getJson("uname=" + uname, "pwd=" + getPassword(pwd));
loginResponse = getPostResponse(url, params);
if (isRight(loginResponse)) {
JSONObject data = loginResponse.getJSONObject("data");
uid = data.getInteger("uid");
token = data.getString("token");
uname = data.getString("uname");
BeanUtil.copyProperties(userInfoBean, data);
logger.info("User: {} logged in successfully!", uname);
} else {
logger.info("User: {} login failed!", uname);
output(loginResponse);
}
}
/** Default password uses last six digits of user ID */
public OkayBase(String uname) {
this(uname, uname.substring(uname.length() - 6));
}
public OkayBase(String uname, String pwd) {
this.uname = uname;
this.pwd = pwd;
login();
}
public OkayBase(int i) {
this(Users.getStuUser(i), Users.getStuUser(i));
}
public OkayBase() {}
public static String getPassword(String pwd) {
return RSAUtils.getPassword(pwd);
}
public OkayBase(OkayBase okayBase) {
this.pwd = okayBase.pwd;
this.uid = okayBase.uid;
this.uname = okayBase.uname;
this.token = okayBase.token;
this.userInfoBean = okayBase.userInfoBean;
this.cookies = okayBase.cookies;
}
public JSONObject getParams() {
JSONObject json = getJson("uid=" + uid, "token=" + token, "uname=" + uname);
json.putAll(Profile.COMMON_PARAMS);
return json;
}
@Override
public HttpGet getGet(String s) {
return FanLibrary.getHttpGet(HOST + s);
}
@Override
public HttpGet getGet(String s, JSONObject jsonObject) {
return FanLibrary.getHttpGet(HOST + s, jsonObject);
}
@Override
public HttpPost getPost(String s) {
return FanLibrary.getHttpPost(HOST + s);
}
@Override
public HttpPost getPost(String s, JSONObject jsonObject) {
return FanLibrary.getHttpPost(HOST + s, jsonObject.toString());
}
@Override
public HttpPost getPost(String s, JSONObject jsonObject, File file) {
return FanLibrary.getHttpPost(HOST + s, jsonObject, file);
}
@Override
public HttpRequestBase getRequest() {
return null;
}
@Override
public void setHeaders(HttpRequestBase httpRequestBase) {
httpRequestBase.addHeader(Common.getRequestIdHeader());
httpRequestBase.addHeader(FanLibrary.getHeader("token", token));
httpRequestBase.addHeader(FanLibrary.getHeader("u", uname));
httpRequestBase.addHeader(FanLibrary.getHeader("appversion", "2.1.3"));
httpRequestBase.addHeader(FanLibrary.getHeader("m", "tv_yst"));
httpRequestBase.addHeader(FanLibrary.getHeader("appName", "com.example.demoapp"));
httpRequestBase.addHeader(FanLibrary.getHeader("rom", "OKAY_EBOOK_4.0.0_OKUI_5.2.0.1_20191128_T"));
if (!cookies.isEmpty()) httpRequestBase.addHeader(FanLibrary.getCookies(cookies));
}
@Override
public JSONObject getResponse(HttpRequestBase httpRequestBase) {
setHeaders(httpRequestBase);
JSONObject response = FanLibrary.getHttpResponse(httpRequestBase);
handleResponseHeader(response);
return response;
}
@Override
public void handleResponseHeader(JSONObject response) {
if (!response.containsKey(HttpClientConstant.COOKIE)) return;
cookies.putAll(response.getJSONObject(HttpClientConstant.COOKIE));
response.remove(HttpClientConstant.COOKIE);
}
@Override
public JSONObject getGetResponse(String s) {
return getResponse(getGet(s));
}
@Override
public JSONObject getGetResponse(String s, JSONObject jsonObject) {
return getResponse(getGet(s, jsonObject));
}
@Override
public JSONObject getPostResponse(String s) {
return getResponse(getPost(s));
}
@Override
public JSONObject getPostResponse(String s, JSONObject jsonObject) {
return getResponse(getPost(s, jsonObject));
}
@Override
public JSONObject getPostResponse(String s, JSONObject jsonObject, File file) {
return getResponse(getPost(s, jsonObject, file));
}
@Override
public boolean isRight(JSONObject jsonObject) {
try {
int code = jsonObject.getJSONObject("meta").getInteger("ecode");
JSONObject data = jsonObject.getJSONObject("data");
return code == 0 && !data.isEmpty();
} catch (Exception e) {
return false;
}
}
public int checkCode(JSONObject jsonObject, RequestInfo requestInfo) {
if (SysInit.isBlack(requestInfo.getHost())) return TEST_ERROR_CODE;
try {
return jsonObject.getJSONObject("meta").getInteger("ecode");
} catch (Exception e) {
logger.warn("Non‑standard response:{}", jsonObject.toString());
}
return TEST_ERROR_CODE;
}
public JSONObject getCookies() {
return cookies;
}
public void setCookies(JSONObject cookies) {
this.cookies = cookies;
}
public static void allOver() {
FanLibrary.testOver();
}
}The class implements IBase and provides methods to build GET/POST requests, attach common headers (including token, user name, app version, and optional cookies), and parse JSON responses. It also includes utility functions for password hashing via RSA, response code checking, and a static allOver method to clean up test resources.
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.
