Skip to main content

Content Starts Here

How Do I Compare Two Dynamic JSON Responses?

Question
How Do I Compare two Dynamic JSON Responses?
Answer
In ReadyAPI, you may need to compare two JSON Responses that can change with each Test run. This can be two REST Responses, a REST Response and a JDBC Response, etc. 

To complete this task you need to create a Groovy Script that pulls the responses from whichever two sources and parses the JSON utilizing JSONPath to compare each value. 

In the provided script example below, we have two JSON strings: "mongoResponse" and "response". The strings have a different number of fields, so we will check whether the "response" is a part of the "mongoResponse".
Note that the " additionalField ": "testValue" element is presented in the "response" value, and cannot be found in the "mongoResponse" value. Please see the below screenshot.
 
User-added image

The script parses the strings and prints out the difference between them, i.e. if some value from the "response" cannot be found in the "mongoResposne". 
You can use this script in the Groovy Test Step or in the Script assertion of a Request Test Step. 
import com.eviware.soapui.support.JsonPathValue
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ArrayNode
import com.fasterxml.jackson.databind.node.ObjectNode
import com.jayway.jsonpath.Configuration
import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider

def String mongoResponse =   "[{\n" +
        "   \"businessUnit\": \"MarketPlace\",\n" +
        "   \"firstName\": \"xyz\",\n" +
        "   \"lastName\": \"ss\",\n" +
        "   \"gender\": \"M\",\n" +
        "   \"memberStatus\": \"Enrolled\",\n" +
        "   \"currentEmail\": \"mongoDB@yahoo.com\",\n" +
        "   \"currentAddress\":    {\n" +
        "      \"addressLine1\": \"\",\n" +
        "      \"city\": \"\",\n" +
        "      \"county\": \"\",\n" +
        "      \"testFieldArray\" : [\"dog\",\"cat\"]\n" +
        "   },\n" +
        "   \"enrollments\": [   {\n" +
        "      \"effectiveDate\": \"2016-01-01T00:00:00Z\",\n" +
        "      \"endDate\": \"2016-12-31T00:00:00Z\",\n" +
        "      \"planProductCode\": \"2998\"\n" +
        "   }],\n" +
        "   \"identifiers\":    {\n" +
        "      \"medicaidID\": null,\n" +
        "      \"medicareID\": null,\n" +
        "      \"alternateID\": null\n" +
        "   },\n" +
        "   \"planDimCk\": \"\",\n" +
        "   \"planCode\": \"\",\n" +
        "   \"ediStateCode\": \"\"\n" +
        "}]"
def String response = "[{\n" +
        "  \"enrollments\": [{\n" +
        "  \"effectiveDate\": \"2016-01-01T00:00:00Z\",\n" +
        "  \"endDate\": \"2016-12-31T00:00:00Z\",\n" +
        "  \"planProductCode\": \"2998\"\n" +
        " }],\n" +
        " \"identifiers\": {\n" +
        "  \"medicaidID\": null,\n" +
        "  \"medicareID\": null,\n" +
        "  \"alternateID\": null,\n" +
        "  \"additionalField\": \"testValue\"\n" +
        " }\n" +
        "}]"
mapper = new ObjectMapper()
JsonNode jsonResponse = mapper.readTree(response);
JsonNode mongoDBResponse = mapper.readTree(mongoResponse);
Set<JsonPathValue> pathValues = listLeafValues(jsonResponse, '$');
Configuration configuration = Configuration.builder()
        .jsonProvider(new JacksonJsonNodeJsonProvider())
        .mappingProvider(new JacksonMappingProvider(mapper))
        .build();

pathValues.each {
    try {
        JsonPath jsonPath = JsonPath.compile(it.path);
        JsonNode result = jsonPath.read(mongoDBResponse, configuration);
        if (result != it.value) {
            log.info('Node with path ' + it.path + ' and value ' + it.value + ' cannot be found')
        }
    } catch (Exception e) {
        log.info('Node with path ' + it.path + ' and value ' + it.value + ' cannot be found')
    }
}

Set<JsonPathValue> listLeafValues(JsonNode jsonObject, String path) {
    if (jsonObject.isObject()) {
        return getValuesFrom((ObjectNode) jsonObject, path);
    } else if (jsonObject.isArray()) {
        return getValuesFrom((ArrayNode) jsonObject, path);
    } else {
    }
}

Set<JsonPathValue> getValuesFrom(ObjectNode jsonObject, String path) {
    Set<JsonPathValue> values = new LinkedHashSet<>();
    Iterator<Map.Entry<String, JsonNode>> fields = jsonObject.fields();
    while (fields.hasNext()) {
        Map.Entry<String, JsonNode> field = fields.next();
        JsonNode value = field.getValue();
        String nodePath = path + "." + field.getKey();
        addValue(values, value, nodePath);
    }
    return values;
}

Set<JsonPathValue> getValuesFrom(ArrayNode array, String nodePath) {
    Set<JsonPathValue> values = new LinkedHashSet<>();
    int index = 0;
    for (JsonNode value : array) {
        addValue(values, value, nodePath + "[" + index + "]");
        index++;
    }
    return values;
}

def addValue(Set<JsonPathValue> values, JsonNode value, String nodePath) {
    if (value.isObject()) {
        values.addAll(getValuesFrom((ObjectNode) value, nodePath));
    } else if (value.isArray()) {
        values.addAll(getValuesFrom((ArrayNode) value, nodePath));
    } else if (value.isValueNode()) {
        values.add(new JsonPathValue(nodePath, value));
    }
}

Note that you can replace the JSON strings with property expansions that point to the responses of a Test Step with the "Get Data" Tool. Please see the details about the Get Data functionality here: https://support.smartbear.com/readyapi/docs/testing/properties/get-data.html
Previous MonthNext Month
SunMonTueWedThuFriSat