How to access the variable in other test RESt Assured - junit

I am new to REST Assured framework. I have written the below code. It's working fine.
private static String result;
#Test
public void getStudentById() {
Response response =
given().
header("authToken",userToken).
pathParam("SNum", "A123").
when().
get("/students/{SNum}").
then().
contentType(ContentType.JSON).
body("firstName",equalTo("JOHN")).
extract().
response();
result = response.print();
System.out.println("Response************************" + result);
}
#Test
public void StTest() {
System.out.println("Response************************" + result);
}
In the response I am getting JSON data
{"list":
[
{
"id": 0,
"SNum": "A123",
"title": "Mr",
"firstName": "JOHN",
"lastName": "Doe"
},
{
"id":1 ,
"SNum": "A12",
"title": "Mr",
"firstName": "James",
"lastName": "Pesr"
}
]
}
Here, I need id in second test. So I am printing result variable in second test but it is getting null. How to get the result variable in second test.

Use the following jsonPath to get id in the second test:
list[1].id
So you should be able to do:
int id = RestAssured.with(response.asString()).getInt("list[1].id");

Related

How to verify stringified json in pact

I am trying to build a pact between two services using asynchronous communication.
This is the code I used for generate the pact:
#ExtendWith(PactConsumerTestExt.class)
#PactTestFor(providerName = "provider", providerType = ProviderType.ASYNCH)
public class StringifiedPactTest {
#Pact(consumer = "consumer", provider = "provider")
public MessagePact generatePact(MessagePactBuilder builder) {
return builder.hasPactWith("provider")
.expectsToReceive("A valid aws sns event")
.withContent(new PactDslJsonBody().stringType(new String[]{"MessageId", "TopicArn"}).stringValue("Message", new PactDslJsonBody().stringType("Value", "Foo").toString()))
.toPact();
}
#Test
#PactTestFor(pactMethod = "generatePact")
public void buildPact(List<Message> messages) {
}
}
And the generated pact is
{
"consumer": {
"name": "consumer"
},
"provider": {
"name": "provider"
},
"messages": [
{
"description": "A valid aws sns event",
"metaData": {
"contentType": "application/json"
},
"contents": {
"TopicArn": "string",
"Message": "{\"Value\":\"Foo\"}",
"MessageId": "string"
},
"matchingRules": {
"body": {
"$.MessageId": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.TopicArn": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "4.0.10"
}
}
}
This means the producer should have a "Message" that matches {"Value" : "Foo"}, any other combination like {"Value" : "Bar" } won't be successful.
Is there any way to add matching rules inside a stringified json?
Thanks!
Here's an anonymised example from a test we have. Hope it's useful. This creates a pact that matches only on type. So on the provider side, when I test against the contract, it doesn't matter what value I have for categoryName for example, as long as it's a stringType:
#PactTestFor(providerName = "provider-service", providerType = ProviderType.ASYNCH)
public class providerServiceConsumerPactTest {
private static String messageFromJson;
#BeforeAll
static void beforeAll() throws Exception {
messageFromJson = StreamUtils.copyToString(new ClassPathResource("/json/pact/consumer-service_provider-service.json").getInputStream(), Charset.defaultCharset());
}
#Pact(provider = "provider-service", consumer = "consumer-service")
public MessagePact providerServiceMessage(MessagePactBuilder builder) {
DslPart body = new PactDslJsonBody()
.object("metaData")
.stringType("origin", "provider-service")
.datetimeExpression("dateCreated", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.closeObject()
.minArrayLike("categories", 0, 1)
.stringType("id", "example data")
.stringType("categoryName", "example data")
.booleanType("clearance", false)
.closeObject()
.closeArray();
return builder
.expectsToReceive("a provider-service update")
.withContent(body)
.toPact();
}
#Test
#PactTestFor(pactMethod = "providerServiceMessage")
public void testProviderServiceMessage(MessagePact pact) {
// State
final String messageFromPact = pact.getMessages().get(0).contentsAsString();
// Assert
JSONAssert.assertEquals(messageFromPact, messageFromJson, false);
}
I'm having exactly the same issue, and unfortunately I don't think it's possible to tell Pact to parse the stringified JSON and look inside it (e.g. to verify that parse(Message).Value === "Foo" in your example).
The best you can do is write a regular expression to match the string you're expecting. This kind of sucks because there's no easy way to ignore the ordering of the JSON keys (e.g. "{\"a\":\"1\", \"b\":\"2\"}" and "{\"b\":\"2\", \"a\":\"1\"}" will compare different) but AFAIK Pact simply lacks the parsing functionality we're looking for, so the only tool it provides is regex.

Error in JSON array comparison customization(sky-screamer)

I have below two JSONs to compare,
expected json:
[
{
"id": 1,
"code": 1,
"createdOn": null,
"lastModifiedOn": null
},
{
"id": 2,
"code": 1,
"createdOn": null,
"lastModifiedOn": null
}
]
actual json
[
{
"id": 1,
"code": 1,
"createdOn": "2019-12-31",
"lastModifiedOn": "2019-12-31",
},
{
"id": 2,
"code": 1,
"createdOn": "2019-12-31",
"lastModifiedOn": "2019-12-31",
}
]
Trying to compare by ignoring couple of nodes using below code
JSONAssert.assertEquals(actualjson, expectedjson,
new CustomComparator(JSONCompareMode.STRICT,
new Customization("createdOn", (o1, o2) -> {
return true;
}),
new Customization("lastModifiedOn", (o1, o2) -> {
return true;
})
)));
but it is failing with below assertion exception,
java.lang.AssertionError: [0].createdOn
Expected: null
got: 2019-12-31
; [0].lastModifiedOn
Expected: null
got: 2019-12-31
; [1].createdOn
Expected: null
got: 2019-12-31
; [1].lastModifiedOn
Expected: null
got: 2019-12-31
how can I compare array of json values with customization object by skipping createdon and lastmodifiedon nodes?
<groupId>org.assertj</groupId>
<version>2.2.1</version>
Yes below code snippet
JSONAssert.assertEquals(actualjson, expectedjson,
new CustomComparator(JSONCompareMode.STRICT,
new Customization("**.createdOn", (o1, o2) -> true),
new Customization("**.lastModifiedOn", (o1, o2) -> true)
)));
Eventually Customization.getCustomization method invoke appliesToPath method , which invoke this.path.matcher(path).matches();
matcher method is from java.util.regex , so if your pattern "**.createdOn" matches with path "[0].createdOn" , "[1].createdOn" then your Customisation will be added CustomComparator which inturn call your method "(o1, o2) -> true"
Approach 1: Parse the JSON and recreate the two object JSONs without the date properties.
Approach 2: Parse the JSON and put an assertion on each property to be compared.
Give a try to JsonUnit it allows you to ignore values, elements or path which should help.
Since SkyScreamer has open issue noted in github I found temporary solution and thought would be helpful for others,
https://github.com/skyscreamer/JSONassert/issues/109
solution:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
List<DomainObject> actualDomainObj = mapper.readValue(actualJson, new TypeReference<List<DomainObject>>() {
});
List<DomainObject> expectedDomainObj = mapper.readValue(expectedJson, new TypeReference<List<DomainObject>>() {
});
assertDomainObjResults(actualDomainObj.get(0), expectedDomainObj.get(0));
private void assertDomainObjResults(DomainObject actual, DomainObject expected) {
softAssertions.assertThat(actual.getId()).isEqualTo(expected.getId());
softAssertions.assertThat(actual.getLastModifiedOn()).isEqualTo(LocalDate.now());
softAssertions.assertThat(actual.getCreatedOn()).isEqualTo(LocalDate.now());
}
accept the answer if someone finds it useful.
I recently created a custom comparator that lets you use regular expressions in the 'expected' JSON:
public class ExtendedJsonComparator extends DefaultComparator {
public ExtendedJsonComparator(JSONCompareMode mode) {
super(mode);
}
#Override
public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
String expected = expectedValue.toString().trim();
String actual = actualValue.toString();
if(expected.startsWith("${") && expected.endsWith("}")) {
String regex = expected.substring(2, expected.length() - 1);
if(!actual.matches(regex)) {
result.fail(prefix, expected, actual);
}
} else {
super.compareValues(prefix, expectedValue, actualValue, result);
}
}
}
For 'expected, you can then do the following, or create a regex to match your date format, if that's something you're testing:
[
{
"id": 1,
"code": 1,
"createdOn": "${.*}",
"lastModifiedOn": "${.*}"
},
{
"id": 2,
"code": 1,
"createdOn": "${.*}",
"lastModifiedOn": "${.*}"
}
]

Rest Assured: extracting list of values from Json Response using java

I have a JSON Response and want to extract list of values from response for e.g all the values of id's present.
{
"page": 2,
"per_page": 3,
"total": 12,
"total_pages": 4,
"data": [
{
"id": 4,
"first_name": "Eve",
"last_name": "Holt",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
},
{
"id": 5,
"first_name": "Charles",
"last_name": "Morris",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"
},
{
"id": 6,
"first_name": "Tracey",
"last_name": "Ramos",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/bigmancho/128.jpg"
}
]
}
I have tried below code but not able to achieve but it is only printing first value of id i.e 4.
public class Get_Request {
public static void main(String[] args) {
RestAssured.baseURI = "https://reqres.in/";
Response res = given()
.param("page", "2")
.when()
.get("/api/users")
.then()
.assertThat()
.contentType(ContentType.JSON)
.and()
.statusCode(200).extract().response();
/*String data = res.jsonPath().getString("data[0].first_name");
System.out.println(data);
*/
List<HashMap<String,Object>> allids = res.jsonPath().getList("data");
HashMap<String,Object> firstid = allids.get(0);
Object a = firstid.get("id");
System.out.println(a);
}
}
I am beginner in rest assured also i am not sure whether we can achieve the same. Any help would be appreciated. Thanks in advance.
Below Code will find all the ids present in the Response and it will print the result like 4 5 6
List<Integer> ids = res.jsonPath().getList("data.id");
for(Integer i:ids)
{
System.out.println(i);
}
That can be done by changing your path to data.id
List<Integer> ids = res.jsonPath().getList("data.id");
Integer id = ids.get(0);
You can use JsonPath wildcards to extracts data from response , which will save you from writing code everytime you have such requirement, use below JsonPath to extract list of Ids from your response :
$..id

Restangular - removing unwanted datas from json objects returned from server

I have created an restangular application which returns a Student object details json from the server, the application is working fine , but the problem is that it is returning student details with other unwanted datas along with it as shown below
Expected Json
{
"id": 1,
"firstName": "Alex",
"lastName": "Sam",
"age": 22
}
Actual Json
{
"id": 1,
"firstName": "Alex",
"lastName": "Sam",
"age": 22,
"route": "print",
"reqParams": null,
"$fromServer": true,
"parentResource": null,
"restangularCollection": false
}
script
var baseAccount = Restangular.one('print',"Alex");
baseAccount.get().then(function (account) {
console.log(JSON.stringify(account));
$scope.data = account; // Only one account
});
java
#GET
#Path("/print/{name}")
#Produces(MediaType.APPLICATION_JSON)
public Student produceJSON( #PathParam("name") String name ) {
Student st = new Student(name, "Sam",22,1);
return st;
}
Take in to account that this info is necessary if you want that Restangular provide services like update or delete this object through Rest services.
For removing this data you have to unrestangularize the object, it's done by stripRestangular().
var rawObject = Restangular.stripRestangular(restangularizedObject);

Swagger UI + MVC 4 Web API Get JSON with object name

I am using swagger ui plugin to document my web api. I want to return JSON object like:
{"Person": {
"Id": 1,
"Name": "John",
"address": {
"Street": "ABC",
"City": "Penrith",
"PostCode": 2034,
"State": "NSW"
},
"DOB": "2013-11-11T00:00:00"
}
}
Notice the Person object name.
I can do this with the following code:
public HttpResponseMessage Get(int id)
{
Person person = new Person { Id = 1, Name = "John", DOB = new DateTime(2013, 11, 11), address = new Address { City = "Penrith", State = "NSW", PostCode = 2034, Street = "ABC" } } ;
return Request.CreateResponse(HttpStatusCode.Accepted, new { Person = person });
}
Unfortunately, because the return type is HttpResponseMessage and not Person itself, Swagger just shows model as HttResponseMessage. That's not what I want.
If I change the return type to Person and return a person object, I don't get the the Person object name in the JSON return. That returns only -
{
"Id": 1,
"Name": "John",
"address": {
"Street": "ABC",
"City": "Penrith",
"PostCode": 2034,
"State": "NSW"
},
"DOB": "2013-11-11T00:00:00"
}
Is there a way to return Person but have the JSON string with Person object name?
Simply create a new class which has a Person property, instance it, assign the value to the Person property and return this object.
In this way, the JSON will look as expected.
If you don't want to create a new class, try using an anonymous type, like this:
// If you have this object
var MyPerson = ...;
// Return this from Web API
return new { Person = MyPersons };
(I don't know if this last option will work for you)