背景
在写API automation cases时,经常会遇到Json格式的request和response。在设计cases时,对json request body会有不同的设置,为了方便,我们可以写个方法满足不同层级的key,value设置。
技术
ObjectMapper 是Jackson 库的一个主要类,它将JSON映射到Java对象(反序列化),或将Java对象映射到JSON(序列化),为了使用Jackson读写json,需要创建Jackson ObjectMapper 实例。
Maven安装,POM中导入:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
JsonNode vs. ObjectNode
JsonNode就是Json格式中的每个字段对象。它是所有JSON节点的基类,它是一个抽象类,绝大多数的get方法均放在了此抽象类里,目的是在不进行类型强制转换的情况下遍历结构。(下图来源网路,源出处不祥,愿owner见谅)
大多数的修改方法都必须通过特定的子类类型去调用,因为在构建/修改某个Node节点时,类型类型信息一般是明确的,而在读取Node节点时大多数时候并不 太关心节点类型。
Jackson JsonNode对象不可变,只可读取,这意味着不能直接构建JsonNode实例的对象图,但你可以创建JsonNode 的子类ObjectNode实例的对象图。
实现
有了上面的基础,我们就可以来实践一把:
创建ObjectMapper实例,读json文件。ResourceReader类
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* Reads the JSON resource file.
*
* @param path String path to file
* @return Document
* @throws IOException e
*/
public static ObjectNode readJsonFile(String path) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = mapper.readValue(getFile(path), ObjectNode.class);
return obj;
}
遍历json文件,设置需要改变的字段值。读取node类型为JsonNode,需要重新设置其值时,应该转换成ObjectNode。针对不同类型(Aarry,string, int)的node做了不同处理。
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.xxxx.infra.services.fw.ResourceReader;
import io.restassured.specification.RequestSpecification;
/**
* sets the json request body from the specified file with the provided
* json value from the feature file
*
* @param request The request
* @param service The service
* @param name The file name
* @param tagValues customerized values for keys
* @return the request body with provided json value
* @throws IOException if there is an issue with an IO operation
*/
public static void setRequestBodyFromJsonFileWithKeysValues(RequestSpecification request, String service, String name, Map<String, String> tagValues)
throws IOException {
String path = "request/body/" + service + "/" + name + ".json";
ObjectNode jsonNodes = ResourceReader.readJsonFile(path);
for (String key : tagValues.keySet()) {
String[] node_list = key.split("\\.");
int nodeCount = node_list.length;
ObjectNode parentNode = jsonNodes;
JsonNode lastNode;
if(nodeCount == 1){
lastNode = parentNode.get(node_list[0]);
}
else {
// travel json node to find the nearest parent node for the provided node
for (int i = 0; i < nodeCount - 1; i++) {
lastNode = parentNode.get(node_list[i]);
parentNode = (ObjectNode)lastNode;
}
lastNode = parentNode.get(node_list[nodeCount - 1]);
}
if (lastNode.isArray()) {
ArrayNode jsonArr = parentNode.withArray(node_list[nodeCount - 1]);
jsonArr.removeAll();
String[] keyValueList = tagValues.get(key).split(",");
for (String value : keyValueList) {
jsonArr.add(value);
}
} else if (lastNode.isTextual() || lastNode.isInt()) {
parentNode.remove(key);
parentNode.put(key, tagValues.get(key));
}
request.body(jsonNodes);
}
}
原json文件:
{
"query": "please input",
"startIndex": 0,
"sortType": "relevance",
"filters": {
"areaOfExpertise": ["Consultant Paediatrician"]
},
"sortOrder": "desc",
"itemsPerPage": 50
}
cucumber feature file中step:
And the body content is in the "webservices" "uk-context-search-with-filters" JSON file with the following keys and value:
| filters.areaOfExpertise | Consultant Paediatric Neurosurgeon,Consultant Paediatrician |
| query | PETER |
| itemsPerPage | 10 |
Request Body中下列字段值已经变化了。
filters.areaOfExpertise
query
itemsPerPage
{
"startIndex": 0,
"sortType": "relevance",
"filters": {
"areaOfExpertise": [
"Consultant Paediatric Neurosurgeon",
"Consultant Paediatrician"
]
},
"sortOrder": "desc",
"query": "PETER",
"itemsPerPage": "10"
}