目前正在着手开发一款功能全面的接口自动化测试平台,该平台将涵盖登录、用户管理、权限控制、项目管理、用例管理、测试数据管理、测试报告生成、任务调度、缺陷跟踪以及系统配置等多个核心模块。为了方便编写测试用例,我们需要通过一些方式来自动获取接口信息,如读取接口文档、调用Swagger接口等方式。本篇内容主要介绍一下通过Swagger接口和Swagger2.0文件来自动化获取接口信息。
通过Swagger获取接口信息详解
技术选型
- 后端:采用Java作为主要开发语言。
- 前端:使用VUE框架进行界面展示。
- SwaggerParser:SwaggerParser是Swagger官方出的Swagger格式解析工具。
数据库表设计
我们需要设计3张表,项目表、接口信息表、接口参数表:
项目表: 记录项目信息,记录项目接口来源(Swagger接口、文档)。
接口信息表: 记录接口信息(url、请求方法、请求类型等)。
接口参数表: 记录接口参数。
获取接口信息方法
根据不同获取接口信息的类型,来获取接口信息数据。urlToJson
方法是根据Swagger接口来获取接口信息:
@Override
public void createApi(ProjectDTO projectDto) throws IOException {
switch (projectDto.getType()) {
case 0:
JSONObject apiJson = urlToJson(projectDto.getApi_url());
swaggerToApi(apiJson, projectDto.getId());
log.info("按swagger接口生成接口信息: {}", apiJson);
break;
case 1:
File file = ResourceUtils.getFile(projectDto.getFile());
String json = new String(Files.readAllBytes(Paths.get(file.getPath())));
JSONObject fileApiJson = JSON.parseObject(json);
swaggerToApi(fileApiJson, projectDto.getId());
log.info("按swagger文档生成接口信息: {}", fileApiJson);
break;
default:
log.warn("不支持的项目类型: {}", projectDto.getType());
}
}
保存数据
将获取的接口信息转成定义的ApiDTO
和DataDTO
实体,并存入到数据库:
private void swaggerToApi(JSONObject jsonObject, Integer id) {
Swagger swagger = new SwaggerParser().parse(jsonObject.toString());
String apiHost = Optional.ofNullable(swagger.getHost()).orElse("");
Map<String, Path> pathsMap = swagger.getPaths();
Map<String, Model> definitionsMap = swagger.getDefinitions();
if (pathsMap != null) {
for (Map.Entry<String, Path> entry : pathsMap.entrySet()) {
String path = entry.getKey();
Path valueMap = entry.getValue();
ApiDTO apiDto = new ApiDTO();
apiDto.setPid(id);
apiDto.setUrl("http://" + apiHost + path);
Operation operation = getOperation(valueMap);
if (operation != null) {
String method = getHttpMethod(valueMap);
apiDto = addApiDto(operation, method, apiDto);
apiMapper.addApi(apiDto);
processParameters(operation, apiDto, definitionsMap);
}
}
}
}
private Operation getOperation(Path path) {
if (path.getGet() != null) {
return path.getGet();
} else if (path.getPost() != null) {
return path.getPost();
} else if (path.getPut() != null) {
return path.getPut();
} else if (path.getDelete() != null) {
return path.getDelete();
}
return null;
}
private String getHttpMethod(Path path) {
if (path.getGet() != null) {
return "GET";
} else if (path.getPost() != null) {
return "POST";
} else if (path.getPut() != null) {
return "PUT";
} else if (path.getDelete() != null) {
return "DELETE";
}
return "";
}
private void processParameters(Operation operation, ApiDTO apiDto, Map<String, Model> definitionsMap) {
List<Parameter> parameters = operation.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
DataDTO dataDto = new DataDTO();
dataDto.setApi_id(apiDto.getId());
if (parameter instanceof BodyParameter) {
processBodyParameter((BodyParameter) parameter, dataDto, definitionsMap);
} else if (parameter instanceof QueryParameter) {
processQueryParameter((QueryParameter) parameter, dataDto);
} else if (parameter instanceof FormParameter) {
processFormParameter((FormParameter) parameter, dataDto);
}
}
}
}
private void processBodyParameter(BodyParameter bodyParameter, DataDTO dataDto, Map<String, Model> definitionsMap) {
String schema = StringUtils.substringAfterLast(Optional.ofNullable(bodyParameter.getSchema())
.map(s -> s.getReference()).orElse(""), "/");
Map<String, Property> map = Optional.ofNullable(bodyParameter.getSchema())
.map(s -> s.getProperties()).orElse(new HashMap<>());
if (schema != null && definitionsMap.containsKey(schema)) {
ModelImpl model = (ModelImpl) definitionsMap.get(schema);
Map<String, Property> properties = model.getProperties();
if (properties != null) {
for (Map.Entry<String, Property> entry : properties.entrySet()) {
Property property = entry.getValue();
fillDataDto(dataDto, entry.getKey(), property);
dataMapper.addData(dataDto);
}
}
} else if (!map.isEmpty()) {
for (Map.Entry<String, Property> entry : map.entrySet()) {
Property property = entry.getValue();
fillDataDto(dataDto, entry.getKey(), property);
dataMapper.addData(dataDto);
}
}
}
private void processQueryParameter(QueryParameter queryParameter, DataDTO dataDto) {
dataDto.setKey(queryParameter.getName());
dataDto.setValue(Optional.ofNullable(queryParameter.getVendorExtensions())
.map(ext -> ext.get("x-example"))
.map(Object::toString)
.orElse(""));
dataDto.setIs_required(queryParameter.getRequired() ? 0 : 1);
dataDto.setType(mapPropertyType(queryParameter.getType(), queryParameter.getItems()));
dataMapper.addData(dataDto);
}
private void processFormParameter(FormParameter formParameter, DataDTO dataDto) {
dataDto.setKey(formParameter.getName());
dataDto.setValue(Optional.ofNullable(formParameter.getVendorExtensions())
.map(ext -> ext.get("x-example"))
.map(Object::toString)
.orElse(""));
dataDto.setIs_required(formParameter.getRequired() ? 0 : 1);
dataDto.setType(mapPropertyType(formParameter.getType(), formParameter.getItems()));
dataMapper.addData(dataDto);
}
private void fillDataDto(DataDTO dataDto, String key, Property property) {
dataDto.setKey(key);
dataDto.setValue(Optional.ofNullable(property.getExample()).map(Object::toString).orElse(""));
dataDto.setType(mapPropertyType(property.getType(), null));
dataDto.setIs_required(property.getRequired() ? 0 : 1);
}
private String mapPropertyType(String type, Property items) {
if (type == null) {
return "string";
}
switch (type) {
case "array":
if (items != null) {
switch (items.getType()) {
case "string":
return "strArray";
case "integer":
return "intArray";
case "object":
return "dictArray";
}
}
return "dict";
case "integer":
return "int";
case "object":
return "dict";
default:
return type;
}
}
private ApiDTO addApiDto(Operation operation, String method, ApiDTO apiDto) {
apiDto.setName(operation.getSummary());
apiDto.setMethod(method.toUpperCase(Locale.ROOT));
apiDto.setData_type(determineDataType(operation, method));
return apiDto;
}
private String determineDataType(Operation operation, String method) {
List<String> consumes = operation.getConsumes();
List<String> produces = operation.getProduces();
if (!"GET".equals(method) && consumes != null && !consumes.isEmpty()) {
return mapContentType(consumes.get(0));
} else if (produces != null && !produces.isEmpty()) {
return mapContentType(produces.get(0));
}
return "GET".equals(method) ? "params" : "";
}
private String mapContentType(String contentType) {
if (contentType.contains("json")) {
return "json";
} else if (contentType.contains("params")) {
return "params";
} else if (contentType.contains("form-data")) {
return "form-data";
} else if (contentType.contains("form-urlencoded")) {
return "form-urlencoded";
}
return "";
}
通过上面的方法,我们实现了自动获取接口信息,也可以根据我们项目实际情况,增加一些拓展,来定制化自己的接口信息获取方法。