I am able to retrieve JSON from a service using RESTAssured.
I would like to use the JSONPath capability to extract JSON and then compare it using JSONAssert.
Here's my example:
#Test
public void doAPITestExample() throws JSONException {
// retrieve JSON from service
Response response = RestAssured.given().get("http://localhost:8081/mockservice");
response.then().assertThat().statusCode(200);
String body = response.getBody().asString();
System.out.println("Body:" + body);
/*
{"datetime": "2018-06-21 17:48:07.488384", "data": [{"foo": "bar"}, {"test": "this is test data"}]}
*/
// able to compare entire body with JSONAssert, strict=false
Object data = response.then().extract().path("data");
System.out.println("Response data:");
System.out.println(data.getClass()); // class java.util.ArrayList
System.out.println(data.toString());
// JSONAssert data with strict=false
String expectedJSON = "{\"data\":[{\"foo\": \"bar\"}, {\"test\": \"this is test data\"}]}";
JSONAssert.assertEquals(expectedJSON, response.getBody().asString(), false);
// How do I extract JSON with JSONPath, use JSONAssert together?
}
Approach 1 - using JSONPath to get JSONObject
How do I get JSONPath to return a JSONObject that can be used by JSONAssert?
In the code example:
Object data = response.then().extract().path("data");
This returns a java.util.ArrayList. How can this be used with JSONAssert to compare to expected JSON?
Approach 2 - parse extracted data with JSONParser
If I do data.toString(), this returns a string that cannot be parsed due to lack of quote handling for string values with spaces strings:
String dataString = response.then().extract().path("data").toString();
JSONArray dataArray = (JSONArray) JSONParser.parseJSON(dataString);
Result:
org.json.JSONException: Unterminated object at character 24 of [{foo=bar}, {test=this is test data}]
Approach 3 - Using JSON schema validation
Is is possible to extract just the data property from the JSON and run that against JSON Schema on just that part?
Note: the entire JSON that is returned is quite large. I just want to validate the data property from it.
What would an example of doing a JSON schema validation look for just the data property from the JSON?
Thanks;
You can use the method jsonPath in your response object.
Example:
// this will return bar as per your example response.
String foo = response.jsonPath ().getString ("data[0].foo");
For more info about JSon path check here.
Related
First off, what do we call a dictionary with a format like this in iOS?
(
{
name = "Apple";
value = "fruit-1";
},
{
name = "Banana";
value = "fruit-2";
}
)
And for my main question. I somehow need to format a string of JSON, like this:
[{"name":"Apple","value":"fruit-1"},{"name":"Banana","value":"fruit-2"}]
into whatever that format is called (of the string above).
For context, the existing approach of my project uses CoreData where the Server response (which uses the mystery format above) gets saved locally as a String, and I want to follow that format.
EDIT: for more context, I really need to just get the first format into the database because a module of a project was built to read the data with that format (e.g. make use of NSString.propertyList()).
Using a library called ios hierarchy viewer, I can see the saved object in the device.
Original format, server json to db (core data) in Objective-C:
What I've been trying to do in Swift, server json to local using JSONSerialization:
First off, what do we call a dictionary with a format like this in iOS?
According to the documentation of NSString.propertyList(), that's a "text representation of a property list".
It's a wonky, non-standard pretty-printing obtained by calling NSArray.description or NSDictionary.description.
Here's an example that shows a round-trip of data:
// The opening `{` indentation is fucky, but that's how it's generated.
let inputPropertyList = """
(
{
name = "Apple";
value = "fruit-1";
},
{
name = "Banana";
value = "fruit-2";
}
)
"""
// The result is an `Any` because we don't know if the root structure
// of the property list is an array or a dictionary
let deserialized: Any = inputPropertyList.propertyList()
// If you want the description in the same format, you need to cast to
// Foundation.NSArray or Foundation.NSDictionary.
// Swift.Array and Swift.Dictionary have a different description format.
let nsDict = deserialized as! NSArray
let roundTrippedPropertyList = nsDict.description
print(roundTrippedPropertyList)
assert(roundTrippedPropertyList == inputPropertyList)
The second format you show is what you get when you display an object in the debug console. That's the output of the object's description property. It isn't a "JSON string", exactly.
If you want to convert your objets to a true JSON string, see below.
As Alexander pointed out, the first string in your question is the output from NSString's propertyList() function. The format looks quite similar to "pretty-printed" JSON, but it's different enough that it it won't work that way.
The `propertyList() function is a debugging-only function, and I don't know of an existing way to parse that back into objects. If that is the string that's being sent by your server, your server is broken. If that's what you see in core data when you log the contents of a field, it's probably a misunderstanding on your part.
To convert an object to pretty JSON, see this answer, where I created an extension to the Encodable format that implements a property "prettyJSON":
extension Encodable {
var prettyJSON: String {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(self),
let output = String(data: data, encoding: .utf8)
else { return "Error converting \(self) to JSON string" }
return output
}
}
That should work for any object that supports the Encodable protocol. (And your object should.)
I want to pass data returned from a soap / xml service to my custom object array. I am not sure if the data I converted to string below is an xml, json or string?
How can I pass the data of cityID and cityName here to my custom city array with cityID and cityName members?
Regards,
That looks like some JSON embedded in XML:) Just get rid of XML stuff and the rest could be simply decoded via JSONDecoder.
The response data was not JSON but JSON embedded in XML, so I first converted the response data to text and removed the HTML tags with below String extension, then I converted that text to json.
extension String{
var removeHTMLTags : String{
return self.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
}
I have a String value being returned from restAssured that I want to convert to a DateTime then validate. One easy way to do this would be:
MockMvcResponse response = this.given
.accept("application/json")
.body(body)
.when()
.put(link)
.then()
.extract().response()
String jsonStr = response.asString()
Map json = strToJson(jsonStr)
assert(MyFixedDateTime.equals(new DateTime(json.dateAttr))
Is there a way to do this without extracting the response?
Follow this link
I think you gonna need to do something similar:
this.given
.accept("application/json")
.body(body)
.when()
.put(link)
.then().body("dateFieldName", equalTo(MyFixedDateTime.toString()))
You can get the required value using JsonPath and convert the returned string to DateTime.
Response response = RestAssured.given ()
.accept("application/json")
.body(body)
.when()
.put(link);
JsonPath jsonPath = JsonPath.from (response.asString ());
String date = jsonPath.get ("responseRoot.dateField"));
DateTime dt = new DateTime (date);
I got the response from REST API into Response object after called through RestAssured API.
Response body is json, i want to get the particular key value from that?
Following is the code
Response res = given()
.relaxedHTTPSValidation()
.with()
.contentType(ConfigReader.get("application.json"))
.then()
.get(url);
String rbody = res.body().asString();
How to get particular key value in rbody string?
Response class has method path() using that, user can give the json path to get the particular value.
Eg:-
Response res = given()
.relaxedHTTPSValidation()
.with()
.contentType(ConfigReader.get("application.json"))
.then()
.get(url);
String value = res.path("root.childKey").toString();
root.childKey is the path of the json element
The JasonPath class that is a part of Restassured is the one that I used for my project. First you need to import the JsonPath class using:
import com.jayway.restassured.path.json.JsonPath;
Then you need to pass the JSON string and use it to create the JsonPath object. From the JsonPath object you can use the key to get the corresponding value. The following code will work for you.
Response res = given()
.relaxedHTTPSValidation()
.with()
.contentType(ConfigReader.get("application.json"))
.then()
.get(url);
String rbody = res.asString();
JsonPath jp = new JsonPath( rbody );
String value = jp.getString( "your.key" );
JSON is formated like this {someProprty:"someValue"} so instead of getting it as a String, you'll want to access that specific property. ie: b.body.someProperty
Note: I strongly encourage you to name your response something more like res or response. You aren't going to enjoy having b as your response.
How to access JSON Object name/value?
JSON can also be formatted like {somePropertyThatIsNumerical:1} or can contain arrays.
baseURI="url";
Map<String,String> reqParam=new HashMap<String,String>();
reqParam.put("loginID","abc");
reqParam.put("password","123");
JSONObject reqObjects=new JSONObject(reqParam);
Response response =
given()
.header("Content-Type", "application/json").accept(ContentType.JSON)
.when()
.body(reqObjects.toJSONString()).post("/v1/getDetails")
.then().log().body().extract().response();
String responseBody= response.asString();
JsonPath path=new JsonPath(responseBody);
String key=path.getString("path.key");
Given I have this JSON array:
{
value: ["000", "111", "345", "987"]
}
I want to use Rest-assured to validate the format of the fields using it's given/when/then structure.
given().
queryParam("myparam", myparamvalue).
when().
get(callRoot).
then().
body("value", matchesPattern("[0-9][0-9][0-9]");
How do I get Rest-assured to loop through and apply the test against each value in the JSON array?
I don't know how many values will be in the JSON array. It might be only 1; it might be 100.
You could use JsonPath and do something like the following:
given().
queryParam("myparam", myparamvalue).
when().
get(callRoot).
then().
body("value.*", matchesPattern("[0-9][0-9][0-9]");
See https://github.com/rest-assured/rest-assured/wiki/usage#json-example for more details.
Or you could extract the response as a String, transform it to a JSONObject, extract the JSONArray in the values field, and then apply the regex to each item in the array:
Response response = given().queryParam("myparam", myparamvalue).when().get(callRoot).
JSONObject responseJson = new JSONObject(response.getBody().asString());
JSONArray values = responseJson.getJSONArray("values");
for(int i = 0; i < values.length(); i++) {
String value = values.getString(i);
Assert.assertThat(values, matchesPattern("[0-9][0-9][0-9]"));
}