更新,主要是解耦代码中的长方法。
在看过一本《代码不朽》的书之后,深受启发,要编写高质量的代码,可维护性一定要弄好,经过尝试,已经将原来的magic()方法修改成为N个短方法,代码逻辑一目了然,分享解耦之后的代码。
非常推荐这本书,虽然很薄,略贵,但干货很多,过些天会分享这本书中的内容。
下面是修改后的swagger.java的代码:
package com.fission.source.until;
import com.fission.source.profile.Constant;
import com.fission.source.source.SourceCode;
import lombok.Data;
import net.sf.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Data
public class Request extends SourceCode {
* 请求的url
private String url;
* 请求类型
private String type;
* 接口名称
private String apiName;
* 接口描述
private String desc;
* restful参数
List<String> restfulArgs = new ArrayList<>();
* query参数
JSONObject args = new JSONObject();
* formdata参数
JSONObject params = new JSONObject();
* 参数替换字符串,用户想方法里面添加参数
StringBuffer stringBuffer = new StringBuffer();
* 代码文本
StringBuffer code = new StringBuffer();
* 如果遇到post请求,fromdata参数为空时,url里面直接拼接请求字符串
boolean postNoParams = false;
* 拼接json参数
* @param i 0:get请求;1:post请求
private void spliceArgs(int i) {
String type = i == 1 ? "params" : "args";
code.append(LINE + TAB + TAB + "JSONObject " + type + " = new JSONObject();");
Set keySet = i == 0 ? args.keySet() : params.keySet();
keySet.forEach(key -> {
// if (!key.toString().equals(LOGINKEY))
collectArgs(key.toString(), params.getString(key.toString()));
code.append(LINE + TAB + TAB + type + ".put(\"" + key.toString() + "\", " + key.toString() + ");");
* 收集参数,拼接往json传参的代码行
* @param key
* @param value
private void collectArgs(String key, String value) {
if (value.equals("string")) stringBuffer.append("String " + key.toString() + ",");
if (value.equals("integer")) stringBuffer.append("int " + key.toString() + ",");
* 收集restful参数,处理url
private void collectRestfulArgs() {
if (url.contains("{")) {//restful公参处理,并提取到restfulargs里面
List<String> regexAll = regexAll(url, "\\{[^}]+\\}");
regexAll.forEach(regex -> {
regex = regex.replace("{", EMPTY).replace("}", EMPTY);
restfulArgs.add(regex);
* 拼接url
* @return
private String spliceUrl() {
collectRestfulArgs();
url = url.contains("{") ? url : url + "\"";
url = "\"" + url.replace("}/{", "+OR+").replace("{", "\"+").replace("}", EMPTY);
return TAB + TAB + "String url = HOST + " + url + ";";
* 拼接get请求
private void spliceGet() {
if (!args.isEmpty()) {
spliceArgs(0);
code.append(LINE + TAB + TAB + "HttpGet httpGet = getHttpGet(url, args);");//拼接获取请求方法
} else {
code.append(LINE + TAB + TAB + "HttpGet httpGet = getHttpGet(url);");//拼接获取请求方法
code.append(LINE + TAB + TAB + "JSONObject response = getHttpResponse(httpGet);");//拼接发送请求获取响应的方法
* 拼接post请求
private void splicePost() {
if (!args.isEmpty()) spliceArgs(0);
if (!params.isEmpty()) spliceArgs(1);
if (args.isEmpty()) {//处理为空的情况
if (!params.isEmpty()) {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url, params);");
} else {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url);");
} else {
if (!params.isEmpty()) {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url, args, params);");
} else {
postNoParams = true;
code.append(LINE + TAB + TAB + "JSONObject response = getHttpResponse(httpPost);");
* 拼接响应后代码行
* @return
private String spliceEnd() {
restfulArgs.forEach(key -> stringBuffer.append("int " + key.toString() + ","));//在方法中添加参数类型的名称
code.append(LINE + TAB + TAB + "output(response);");//拼接输出响应
code.append(LINE + TAB + TAB + "return response;");//返回响应
code.append(LINE + TAB + "}");
return code.toString().replace("() {", "(" + stringBuffer.toString() + ") {").replace(",)", ")");//替换参数类型和名称
* 把request对象变成代码的方法
* @return
public String magic() {
code.append(TAB + "/**\n\t * " + desc + "\n\t *\n\t * @return\n\t */" + LINE);
code.append(TAB + "public JSONObject " + apiName + "() {" + LINE);//新建方法行
String urlLine = spliceUrl();
code.append(urlLine);
if (restfulArgs.size() > 0) restfulArgs.forEach(arg -> args.remove(arg));//将公参从args里面删除
if (type.equals(REQUEST_TYPE_GET)) spliceGet();
if (type.equals(REQUEST_TYPE_POST)) splicePost();
String finalCode = spliceEnd();
if (postNoParams) finalCode.replace(urlLine, urlLine.replace(";", EMPTY) + " + changeJsonToArguments(args)");
return finalCode;
}
---------------------分割线-----------------------
本人在做接口测试的过程中,都是用java代码实现的接口请求,其中很多部分都是重复的或者有规律的。
本着凡事重复的皆可自动化的精神。在跟开发同学沟通确认之后,有了一套方案,接口文档一律采用swagger的形式,get接口传query参数,post请求传formdata参数,(文件上传除外)公参一律header。在规范接口文档之后,我通过解析swagger的json数据,就可以自动生成测试代码了,用了几天,解决了几个bug之后,现在尚且稳定可靠,分享代码供大家参考。
顺道说一句:一定先跟开发约定好规范,不然会很惨。
我会先把swagger的json数据根据那么或者url解析成具体的request对象,然后根据需要把request对象输出成代码。
package com.fission.source.until;
import com.fission.source.source.ApiLibrary;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import javax.naming.Name;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class Swagger extends ApiLibrary {
* 关键字,用于url前
String key;
* swagger文档地址
String swaggerPath;
* 构造方法中接口地址类别
String name;
* 构造方法中接口地址
String url;
* swagger地址所有类别
List<String> names = new ArrayList<>();
* 某类别所有接口地址
List<String> urls = new ArrayList<>();
* swagger文档转换成的json对象
JSONObject swagger = new JSONObject();
* 所有接口地址的json对象
JSONObject paths = new JSONObject();
* 对应构造方法中url的request对象
Request request = new Request();
* 对应构造方法中name的所有request对象
List<Request> requests = new ArrayList<>();
public static void main(String[] args) {
String surl = "http://10.10.32.158:6005/swagger.json";
String sname = "公会初始模块";
Swagger swagger = new Swagger(surl, sname);
swagger.requests.forEach(request1 -> request1.magic());
testOver();
* 获取某一类的接口的request对象
* @param swaggerPath
* @param name
public Swagger(String swaggerPath, String name) {
this.swaggerPath = swaggerPath;
this.name = name;
build();
* 获取某一类的某一个接口的request对象
* @param swaggerPath
* @param name
* @param url
public Swagger(String swaggerPath, String name, String url) {
this.swaggerPath = swaggerPath;
this.name = name;
this.url = url;
build();
request = getRequest(url);
public String getKey() {
key = regexAll(swaggerPath, "/((?!/).)*/swagger.json").get(0);
key = key.replace(OR, EMPTY).replace("swagger.json", EMPTY);
if (key.contains(":")) key = EMPTY;
return this.key;
* 获取name下所有接口的request对象
private void getRequests() {
urls.forEach(url -> {
Request request = getRequest(url);
if (request != null) requests.add(request);
* 初始化处理方法
public void build() {
swagger = getHttpResponse(getHttpGet(swaggerPath));
getKey();
getNames();
getPaths();
getUrls();
getRequests();
* 获取某一个url地址的请求request对象
* @param url 接口地址
* @return
private Request getRequest(String url) {
Request request = new Request();
request.setUrl((OR + key + url).replace("//", "/"));
JSONObject json1 = paths.getJSONObject(url);
JSONObject json2 = new JSONObject();
if (json1.containsKey("get")) {
request.setType(REQUEST_TYPE_GET);
json2 = json1.getJSONObject("get");
} else if (json1.containsKey("post")) {
request.setType(REQUEST_TYPE_POST);
json2 = json1.getJSONObject("post");
String tags = json2.get("tags").toString();
if (!tags.contains(name)) return null;
String apiName = json2.getString("operationId");
request.setApiName(apiName);
String desc = json2.getString("summary");
request.setDesc(desc);
JSONArray json3 = json2.getJSONArray("parameters");
JSONObject json5 = new JSONObject();
JSONObject json6 = new JSONObject();
json3.forEach(json -> {//获取参数,区分query和formdata
JSONObject json4 = (JSONObject) json;
String in = json4.getString("in");
if (in.equals("query")) {
boolean required = json4.getBoolean("required");
if (required) {
String format = json4.getString("type");
String name = json4.getString("name");
json5.put(name, format);
} else if (in.equals("formData")) {
boolean required = json4.getBoolean("required");
if (required) {
String format = json4.getString("type");
String name = json4.getString("name");
json6.put(name, format);
request.setArgs(json5);
request.setParams(json6);
return request;
* 获取name下所有接口的地址
private void getUrls() {
Set keySet = paths.keySet();
keySet.forEach(key -> urls.add(key.toString()));
* 获取所有name
private void getNames() {
JSONArray tags = swagger.getJSONArray("tags");
tags.forEach(info -> {
JSONObject name = (JSONObject) info;
names.add(name.getString("name"));
* 获取所有的接口地址
private void getPaths() {
paths = swagger.getJSONObject("paths");
}
下面是request类:
package com.fission.source.until;
import com.fission.source.profile.Constant;
import com.fission.source.source.SourceCode;
import net.sf.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Request extends SourceCode {
* 请求的url
private String url;
* 请求类型
private String type;
* 接口名称
private String apiName;
* 接口描述
private String desc;
* restful参数
List<String> restfulArgs = new ArrayList<>();
* query参数
JSONObject args = new JSONObject();
* formdata参数
JSONObject params = new JSONObject();
* 把request对象变成代码的方法
* @return
public String magic() {
StringBuffer code = new StringBuffer(Constant.TAB + "/**\n\t * " + desc + "\n\t *\n\t * @return\n\t */" + LINE);
code.append(TAB + "public JSONObject " + apiName + "() {" + LINE);//新建方法行
if (url.contains("{")) {//restful公参处理,并提取到restfulargs里面
List<String> regexAll = regexAll(url, "\\{[^}]+\\}");
regexAll.forEach(regex -> {
regex = regex.replace("{", EMPTY).replace("}", EMPTY);
restfulArgs.add(regex);
url = url.contains("{") ? url : url + "\"";
url = "\"" + url.replace("}/{", "+OR+").replace("{", "\"+").replace("}", EMPTY);
String urlLine = TAB + TAB + "String url = HOST + " + url + ";";
code.append(urlLine);
StringBuffer stringBuffer = new StringBuffer();//参数替换字符串,用户想方法里面添加参数
boolean postNoParams = false;//如果遇到post请求,fromdata参数为空时,url里面直接拼接请求字符串
if (restfulArgs.size() > 0) restfulArgs.forEach(arg -> args.remove(arg));//将公参从args里面删除
if (type.equals(REQUEST_TYPE_GET)) {
if (!args.isEmpty()) {
code.append(LINE + TAB + TAB + "JSONObject args = new JSONObject();");
Set keySet = args.keySet();
keySet.forEach(key -> {//拼接get请求参数,json类型,排除公参
if (!key.toString().equals(LOGINKEY)) {
String value = params.getString(key.toString());
if (value.equals("string")) {
stringBuffer.append("String " + key.toString() + ",");
} else if (value.equals("integer")) {
stringBuffer.append("int " + key.toString() + ",");
code.append(LINE + TAB + TAB + "args.put(\"" + key.toString() + ", " + key.toString() + ");");
code.append(LINE + TAB + TAB + "HttpGet httpGet = getHttpGet(url, args);");//拼接获取请求方法
} else {
code.append(LINE + TAB + TAB + "HttpGet httpGet = getHttpGet(url);");//拼接获取请求方法
code.append(LINE + TAB + TAB + "JSONObject response = getHttpResponse(httpGet);");//拼接发送请求获取响应的方法
} else if (type.equals(REQUEST_TYPE_POST)) {
boolean argsEmpty = args.isEmpty();//querty参数是否为空
boolean paramsEmpty = params.isEmpty();//formdata参数是否为空
if (!argsEmpty) {
code.append(LINE + TAB + TAB + "JSONObject args = new JSONObject();");
Set keySet = args.keySet();
keySet.forEach(key -> {//拼接query请求参数,json类型,排除公参
if (!key.toString().equals(LOGINKEY)) {
String value = params.getString(key.toString());
if (value.equals("string")) {
stringBuffer.append("String " + key.toString() + ",");
} else if (value.equals("integer")) {
stringBuffer.append("int " + key.toString() + ",");
code.append(LINE + TAB + TAB + "args.put(\"" + key.toString() + ", " + key.toString() + ");");
if (!paramsEmpty) {
code.append(LINE + TAB + TAB + "JSONObject params = new JSONObject();");
Set keySet = params.keySet();
keySet.forEach(key -> {
if (!key.toString().equals(LOGINKEY)) {
String value = params.getString(key.toString());
if (value.equals("string")) {
stringBuffer.append("String " + key.toString() + ",");
} else if (value.equals("integer")) {
stringBuffer.append("int " + key.toString() + ",");
code.append(LINE + TAB + TAB + "params.put(\"" + key.toString() + "\", " + key.toString() + ");");
if (argsEmpty) {//处理为空的情况
if (!paramsEmpty) {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url, params);");
} else {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url);");
} else {
if (!paramsEmpty) {
code.append(LINE + TAB + TAB + "HttpPost httpPost = getHttpPost(url, args, params);");
} else {
postNoParams = true;
code.append(LINE + TAB + TAB + "JSONObject response = getHttpResponse(httpPost);");
restfulArgs.forEach(key -> stringBuffer.append("int " + key.toString() + ","));//在方法中添加参数类型的名称
code.append(LINE + TAB + TAB + "output(response);");//拼接输出响应
code.append(LINE + TAB + TAB + "return response;");//返回响应
code.append(LINE + TAB + "}");
String finalCode = code.toString().replace("() {", "(" + stringBuffer.toString() + ") {").replace(",)", ")");//替换参数类型和名称
if (postNoParams)//如果post请求,formdata参数为空,query参数直接拼接在url里面
finalCode.replace(urlLine, urlLine.replace(";", EMPTY) + " + changeJsonToArguments(args)");
output(finalCode);
return finalCode;
public String getUrl() {
return url;
public void setUrl(String url) {
this.url = url;
public String getType() {
return type;
public void setType(String type) {
this.type = type;
public String getApiName() {
return apiName;
public void setApiName(String apiName) {
this.apiName = apiName;
public String getDesc() {
return desc;
public void setDesc(String desc) {
this.desc = desc;
public JSONObject getArgs() {
return args;
public void setArgs(JSONObject args) {
this.args = args;
public JSONObject getParams() {
return params;
public void setParams(JSONObject params) {
this.params = params;
public List<String> getRestfulArgs() {
return restfulArgs;
public void setRestfulArgs(List<String> restfulArgs) {