How to validate entire JSON with 1 dynamic field with JMeter - json

I have a JSR223 Assertion in JMeter that validates entire JSON response and its working.
The problem is that each time I insert data in DB one of JSON fields changes and validation fails.
How could I skip that dynamic field from response validation?
Response JSON example:
[
{
"id": "273444",
"trxDateTime": "2019-03-25T22:38:16Z",
"merchantName": "MerchECOM1",
"merchantTransId": "1r1vXue4qn",
"trxType": "Payment",
"paymentBrand": "MasterCard",
"amount": 20.00,
"currencyCode": "AUD",
"status": "Declined",
"statusResponseMessage": null,
"customerAccount": "123456"
}
]
JSR223 Assertion:
def expected = new groovy.json.JsonSlurper().parseText(vars.get('expected1'))
def actual = new groovy.json.JsonSlurper().parse(prev.getResponseData())
if (expected != actual) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage('Mismatch between expected and actual JSON')
}
just with this I'm not able to validate the dynamic "id" field
any idea?
Thanks in advance

If you're not interested in this id field - just remove it from the expected variable and the actual response, to wit amend first 2 lines of your assertion to look like:
def expected = new groovy.json.JsonSlurper().parseText(vars.get('expected1')).each {entry -> entry.remove('id')}
def actual = new groovy.json.JsonSlurper().parse(prev.getResponseData()).each {entry -> entry.remove('id')}
More information:
Groovy: Parsing and Producing JSON
Apache Groovy - Why and How You Should Use It
Demo:

If value is not your concern for id field you can directly use regex matcher to check the field using Jsonassertion by specifying jsonpath and check match as regex use regex

Related

Groovy parse Json preserve keys order

I try to parse a Json in groovy/Jenkins(I have no access to readJSON step) and keep the json keys order.
After my research, I found that groovy Map/HashMap objects are not preserving the order of the keys.
The only type which keeping order is LinkedHashMap So I try to convert the output of JsonSlurper.parseText to linkedhashmap but it still changing the items order
def jsonstr = """
{
"Id": 533,
"StartTime": "2022-05-10 11:56:18",
"EndTime": "2022-05-10 11:58:49",
"TimeShift": "N/A",
"Run": "123",
"Setup": "Test",
"Version": "3.17",
"Result": "pass",
"DebugMode": 1,
"NumberOfCores": 3,
}
"""
//init as LinkedHashMap
LinkedHashMap map = new LinkedHashMap()
map = (LinkedHashMap) (new JsonSlurperClassic().parseText(jsonstr))
println(map)
/*
the output is in incorrect order, I expect to get `Id` attribute as a first key but I'm getting:
[EndTime:2022-05-10 11:58:49, Version:3.17, TimeShift:N/A, StartTime:2022-05-10 11:56:18, DebugMode:1, Run:123, NumberOfCores:3, Id:533, Setup:Test, Result:pass]
*/
Here is the solution:
I realized that readJSON step is keeping the order so I try to take a look at its implementation.
readJSON uses net.sf.json.* library, in this library there is an option to parse string to jsonObject (with keeping the order of the keys!) by:
import net.sf.json.JSONSerializer
def map = JSONSerializer.toJSON(jsonstr)
println(map)
NOTES:
if you want use it during a pipeline I suggest you to use readJSON step itself, otherwise, you'll need to approve this function from Manage Jenkins -> script approval
In this method empty properties will be net.sf.json.JSONNull
which holds a textual value "null" -> if (someEmptyKey != null) always returns true (also when null) to avoid that, use:
if (!someEmptyKey instanceof JSONNull )
Sources: docs, jenkins-implementation

How to filter a complex response in karate dsl using jsonPath?

I am getting below response from a REST API, but I am finding it difficult to extract label value from the received response and assign it to a variable to use it later in script.
Here is the RESPONSE::
{
"result": "SUCCESS",
"rawAttr": "[{\"attributes\":[{\"name\":\"resourceid\",\"value\":\"7A7Q123456\"},{\"name\":\"physicalid\",\"value\":\"7A7Q123456\"},{\"name\":\"dsw:label\",\"value\":\"MY Product00004285\"},{\"name\":\"dsw:created\",\"value\":\"2019-11-06T08:39:39Z\"}]}]",
"physicalid": "7A7Q123456",
"contextPath": "/path",
"id": "7A7Q123456",
"message": null
}
I am able to get response.id and response.result which is helpful for validation but I am not able to get the dsw:label value which is MY Product00004285
When I do def Arr = response.rawAttr I get the below value whether it is Array or String I am confused. Seems like it is a string.
[{"attributes":[{"name":"resourceid","value":"7A7Q123456"},{"name":"physicalid","value":"7A7Q123456"},{"name":"dsw:label","value":"MY Product00004298"},{"name":"dsw:created","value":"2019-11-06T08:39:39Z"}]}]
It is very easy to extract the label in JMeter JSON Extractor using below JSON Path expression
$.attributes.value[2]
Refer Karate's type conversion capabilities: https://github.com/intuit/karate#type-conversion
So you can do this:
* json attr = response.rawAttr
And then you are all set.
Thanks to an example and documentation on converting string to json.
Got it how to do.
And def strVar = response.rawAttr
And json jsonVar = strVar
And def attrb = karate.jsonPath(jsonVar, '$..attributes.[2].value')[0]
And print '\n\n Attrb\n', attrb
Links I referred:
Json Path evaluator
Karate doc reference for type conversion
Karate example for type-conversion

Length is not worked in JSON Extractor in Jmeter

I need to get the count of card from json file. For this I've used $.storedCards.cards.lenght
in JSON Extractor but it doesn't work. There is an error message:
Options AS_PATH_LIST and ALWAYS_RETURN_LIST are not allowed when using path functions!
After that I've tried JSR223 PostProcessor with next script on goovy
def jsonText = '''${AllCards}''' //${AllCards} has json value
def json = new JsonSlurper().parseText(jsonText)
log.info( "Json length---------->"+json.resource.size())
${CardsCount} = props.get("4") //vars.put(json.resource.size.toString())
but there is problem with set value to my variable. Or when i've created variable in Groovy it was impossible to use outside from script.
My json file
"storedCards":
{
"cards":
[
{
"CardId":"123",
"cardBrand":"Visa",
"lastFourDigits":"2968",
},
{
"CardId":"321",
"cardBrand":"Visa",
"lastFourDigits":"2968",
},
..........
],
How can i get the count of card and set to my Variables? what should i use for this?
Your JSON data seems to be invalid. Assuming you have the valid JSON like below, I'm answering your question.
{
"storedCards": {
"cards": [
{
"CardId": "123",
"cardBrand": "Visa",
"lastFourDigits": "2968"
},
{
"CardId": "321",
"cardBrand": "Visa",
"lastFourDigits": "2968"
}
]
}
}
You dont need to write Groovy code, you can resolve this using JSON Extractor. Instead of using length function, use JSON path predicate like this-
$.storedCards.cards[*]
Though Variable you used in JSON Extractor won't give the solution right away, another JMeter function helps - __RandomFromMultipleVars
Excerpt from documentation -
The RandomFromMultipleVars function returns a random value based on the variable values provided by Source Variables.
The variables can be simple or multi-valued as they can be generated by the following extractors:
Boundary Extractor
Regular Expression Extractor
CSS Selector Extractor
JSON Extractor
XPath Extractor
XPath2 Extractor
Multi-value vars are the ones that are extracted when you set -1 for
Match Numbers. This leads to creation of match number variable called
varName_matchNr and for each value to the creation of variable
varName_n where n = 1, 2, 3 etc.
So once you use the predicate, you will get the count in the yourVariableName_matchNr. Example:-
Hope this help.

JSON Path PostProcessor: storing JSON arrays and objects loses their data type

I'm using JSON Path PostProcessor with path expressions to store a JSON object from a JSON response, but when I later retrieve the variable, it has been reduced to string with key - pair values. So I don't know that was a string or number.
Example:
Response looks like this
{
.
.
"currency" : {
"code" : "AUD",
"name" : "Australian Dollars",
"symbol" : "$"
},
.
}
Using the path expression, I find currency and save it.
However, when I use it in a HTTP Request body data ("currency" : ${currency},),
it comes like this:
"currency" : {code=AUD, name=Australian Dollars, symbol=$},
How do I get the JSON Path PostProcessor to save the JSON object 'as is" without losing the data type details? Should I be using a different approach instead of JSON Path?
I would recommend switching to JSR223 PostProcessor and Groovy language, this way you will have full control of what is going on and be able to do what you want.
Assuming you have the following JSON response:
{
"currency": {
"code": "AUD",
"name": "Australian Dollars",
"symbol": "$"
}
}
the relevant Groovy coode will be something like:
def json = new groovy.json.JsonSlurper().parse(prev.getResponseData())
def currency = json.currency
def currencyString = new groovy.json.JsonBuilder(currency).toPrettyString()
vars.put('currency', currencyString)
log.info(currencyString)
Demo:
References:
Groovy - Learn
Groovy - Parsing and producing JSON
Groovy is the New Black

SOAP UI Assertion Help : To validate Total attribute and Total Value

I searched in Google and Stackoverflow and I didn't find any helpful information and decide to post question.
I am getting response from API in JSON.
{
"CouponCode": [{
"id": 56,
"name": "BlackFriday"
}, {
"id": 58,
"name": "ThanksGiving"
}, {
"id": 62,
"name": "New Year"
}]}
I need to add assertion that will count that there are total 3 id and 3 name.
All IDs and Names are not empty. We don't want to send empty attribute value.
I am using SOAP UI open source. Please provide exact code or exact reference.
Exactly assertion needs to
Find total Ids and Name that's will be size
Find total Ids and Name size.
If Id is 3 and 3 Ids value are three..if JSON come like in this case assertion will failed.
this
{
"CouponCode": [{
"id": 56,
"name": "BlackFriday"
}, {
"id": 58,
"name": "ThanksGiving"
}, {
"id": "",
"name": "New Year"
}]}
The below groovy script uses json way to check the expected results.
Add the groovy script step after the rest request step in your test case.
Sudo code for extracting the same.
Read the json text. If you do not want to use fixed response, read it from previous step response. Create the object.
Make sure you have the expected counts for id, and name. You may also define them at test case custom properties in case do not want to use fixed values and change each time in the script.
find all the id count and check with expected value and show the error message in case of failure.
Similar to step 3, do the assert for names.
//for testing using fixed response, you may aslo assign dynamic response.
def jsonText = '''
{
"CouponCode": [{
"id": 56,
"name": "BlackFriday"
}, {
"id": 58,
"name": "ThanksGiving"
}, {
"id": 62,
"name": "New Year"
}]}'''
def coupons = new groovy.json.JsonSlurper().parseText(jsonText).CouponCode
//You may also read these values from test case properties
def expectedIdCount = 3
def expectedNameCount = 3
//assert the expected id count with find all coupon ids count of json response
assert expectedIdCount == coupons.findAll{it.id}.size(), "Coupon id count does not match"
//assert the expected name count with find all coupon names count of json response
assert expectedNameCount == coupons.findAll{it.name}.size(), "Coupon name count does not match"
The same can be achieved using script assertion for the rest step as well, that will avoid additional groovy script step. But it may require little changes in the script as below.
How to read the json response dynamically?
From script assertion
Use below line and remove the fixed jsonText from above.
def jsonText = messageExchange.response.responseContent
From Groovy script step
//replace the rest request step name below
def jsonText = context.expand('${ReplaceStepName#Response}')
How to read the test case level properties for expected results instead of hardcoded values in the script?
Define a test case level property for id, say EXPECTED_ID_COUNT and provide value 3 like you mentioned and similarly, define for name as well.
//read in script these properties
def expectedIdCount = context.testCase.getPropertyValue('EXPECTED_ID_COUNT') as Integer
There are several possible solutions. The easiest is to use an XPath assertion; keep in mind that internally, SoapUI converts everything to XML if it can.
count(//*:id)
expected result:
3
Similarly for your name.