我们正在创建一个REST API,使用Swagger的@ApiModelProperty
注释进行记录。我正在为API编写端到端测试,我需要为某些请求生成JSON主体。假设我需要将以下JSON发布到端点:
{ "name": "dan", "age": "33" }
到目前为止,我创建了一个单独的类,其中包含所有必需的属性,并且可以使用Jackson序列化为JSON:
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyPostRequest {
private String name;
private String age;
// getters and fluid setters omitted...
public static MyPostRequest getExample() {
return new MyPostRequest().setName("dan").setAge("33");
}
}
但是,我们注意到我们在代码库中已经有一个非常相似的类,它定义了API接受的模型。在此模型类中,每个属性的示例值已在@ApiModelProperty
:
@ApiModel(value = "MyAPIModel")
public class MyAPIModel extends AbstractModel {
@ApiModelProperty(required = true, example = "dan")
private String name;
@ApiModelProperty(required = true, example = "33")
private String age;
}
是否有一种简单的方法来生成一个MyAPIModel实例,其中填充了每个属性的示例值?注意:我需要能够在转换为JSON之前修改端到端测试中的单个属性,以便测试不同的边缘情况。因此,直接生成示例JSON是不够的。
基本上,我可以在MyAPIModel上编写一个静态方法getExample()(甚至在基类AbstractModel上更好),它返回Swagger注释中指定的MyAPIModel的示例实例吗?
答案 0 :(得分:1)
截至本回答时,这似乎不可能。我找到的最接近的可能性是:
io.swagger.converter.ModelConverters
:方法read()
创建Model
个对象,但这些模型中的example
成员为空。这些示例以String形式存在于properties
成员中(直接取自APIModelParameter注释)。
io.swagger.codegen.examples.ExampleGenerator
:方法resolveModelToExample()
从ModelConverters.read()
获取输出,并生成一个表示对象及其属性的Map(同时还解析非字符串属性,如嵌套楷模)。此方法用于序列化为JSON。不幸的是,resolveModelToExample()
是私有的。如果它是公共可访问的,那么为带注释的Swagger API模型类生成模型默认值的代码可能如下所示:
protected <T extends AbstractModel> T getModelExample(Class<T> clazz) {
// Get the swagger model instance including properties list with examples
Map<String,Model> models = ModelConverters.getInstance().read(clazz);
// Parse non-string example values into proper objects, and compile a map of properties representing an example object
ExampleGenerator eg = new ExampleGenerator(models);
Object resolved = eg.resolveModelToExample(clazz.getSimpleName(), null, new HashSet<String>());
if (!(resolved instanceof Map<?,?>)) {
// Model is not an instance of io.swagger.models.ModelImpl, and therefore no example can be resolved
return null;
}
T result = clazz.newInstance();
BeanUtils.populate(result, (Map<?,?>) resolved);
return result;
}
protected <T extends MyModelBaseClass> T getModelExample(Class<T> clazz) {
try {
T result = clazz.newInstance();
for(Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(ApiModelProperty.class)) {
String exampleValue = field.getAnnotation(ApiModelProperty.class).example();
if (exampleValue != null) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
setField(result, field, exampleValue);
field.setAccessible(accessible);
}
}
}
return result;
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException("Could not create model example", e);
}
}
private <T extends MyModelBaseClass> void setField(T model, Field field, String value) throws IllegalArgumentException, IllegalAccessException {
Class<?> type = field.getType();
LOGGER.info(type.toString());
if (String.class.equals(type)) {
field.set(model, value);
} else if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
field.set(model, Boolean.parseBoolean(value));
} else if (Integer.TYPE.equals(type) || Integer.class.equals(type)) {
field.set(model, Integer.parseInt(value));
}
}
我可能会在Github上打开一个Issue / PR,建议为Swagger添加功能。我很惊讶没有其他人似乎要求这个功能,因为我们将示例模型实例作为测试发送到API的用例应该是常见的。