I'm new to SoapUI. I wanted to know how can we add 2 property value into one Header value.
For instance, I got some response like in XML format:
<Response xmlns="Http://SomeUrl">
<access_token>abc</access_token>
<scope>scope1</scope>
<token_type>Bearer</token_type>
</Response>
I want to send both access_token & token type to a single header value like:
"Authorization":"Bearer abc"
I am not getting how to do this using property transfer step.
Can anyone please help me?
You can use XPath concat function to concatenate the both values in one variable in your property transfer steps, in your case you can use the follow XPath:
concat(//*:token_type," ",//*:access_token)
concat function concatenates two or more strings, //*:token_type gets the Bearer value and //*:access_token gets the abc.
Hope this helps,
Add a script step after the step returning what you describe above.
def tokenType = context.expand('${STEP RETURNING STUFF#Response#//Response/token_type}');
def token = context.expand('${STEP RETURNING STUFF#Response#//Response/access_token}');
//add header to all steps
for (def stepEntry : testRunner.testCase.testSteps) {
if (!(stepEntry.value instanceof com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep)) {
continue;
}
def headers = stepEntry.value.httpRequest.requestHeaders;
headers.remove("Authorization");
headers.put("Authorization", token_type + " " + token);
stepEntry.value.httpRequest.requestHeaders = headers;
}
Here is another way without using additional property transfer step, but uses script assertion
Add a script assertion for the request test step.
Use below code into that script, modify element XPath are required
def element1Xpath = '//*:token_type'
def element2Xpath = '//*:access_token'
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def response = groovyUtils.getXmlHolder(messageExchange.responseContentAsXml)
def field1 = response.getNodeValue(element1Xpath)
def field2 = response.getNodeValue(element2Xpath)
if (!field1) { throw new Error ("${element1Xpath} is either empty or null") }
if (!field1) { throw new Error ("${element2Xpath} is either empty or null") }
context.testCase.setPropertyValue('TEMP_PROPERTY', "${field1} ${field2}")
Now the expected value(merged) is available in a property 'TEMP_PROPERTY'. You may rename the property name as you wish in the last line of the code.
You may the new wherever it is needed within the test case.
Related
I want to test an endpoint using jmeter, that has a copule of query string parameters, one of which is optional, loading the values from a CSV file. The problem is, can I avoid sending the query string parameter if I don't have a value for it?
It is but it will require some Groovy coding
Add JSR223 PreProcessor as a child of the request which query string you want to modify (or according to JMeter Scoping Rules if you want to apply the approach to more than one request)
Put the following code into "Script" area:
def newData = new org.apache.jmeter.config.Arguments()
0.upto(sampler.getArguments().size() - 1, { idx ->
def arg = sampler.getArguments().getArgument(idx)
if (!arg.getValue().equals('')) {
newData.addArgument(arg)
}
})
sampler.setArguments(newData)
That's it, the PreProcessor will be executed before the HTTP Request sampler and will remove all arguments which don't have their respective values
I have this script in JMeter, PUT method,
how can i remove a path variable if the value from the input data is blank?
I know i can remove this if the parameter were in the Parameter tab of the HTTP request using the remove Arguments, the thing is I have a value in the body data so I have to put the URL parameters in the path that's why remove arguments is not working anymore.
code:
if ("${thisfromCSV}" == "") {
sampler.getArguments().removeArgument("thisParameter");
}
this works if the parameter is located at the Parameters tab of the HTTP Request
Add JSR223 PreProcessor as a child of the HTTP Request you would like to modify
Put the following code into "Script" area:
def url = new URL("http://example.com" + sampler.getPath())
def params = url.query.split('&').collectEntries({ param ->
param.split('=').collect {
URLDecoder.decode(it, 'UTF-8')
}
})
if (vars.get('thisfromCSV') == '') {
params.remove('thisParameter')
}
def query = params.collect { k, v -> "$k=$v" }.join('&')
sampler.setPath(url.path + '?' + query)
That's it, the code will remove thisParameter from the Sampler's URL query string in case of thisfromCSV variable is empty.
See Apache Groovy - Why and How You Should Use It for more information on using Groovy scripting in JMeter tests.
How do I test for the correct test results when my returned array is unordered? My test fails because the order they are in the array is different on each test run. How can I fix this or account for an unordered array?
mockMvc.perform(delete("/deleteSomeObject" + "/objIdLong" + "/objFKeyString"))
.
.
.andExpect(jsonPath("$[0].id.objIdLong", is(533252)))
.andExpect(jsonPath("$[0].id.objFKeyString", is("SomeString")))
.andExpect(jsonPath("$[1].id.objIdLong", is(642654252)))
.andExpect(jsonPath("$[1].id.objFKeyString", is("ThisString")))
.andExpect(jsonPath("$[2].id.objIdLong", is(4624352)))
.andExpect(jsonPath("$[2].id.objFKeyString", is("SomeOtherString")));
You could use the 'any element' instruction and to prevent false positives where one element has the expected objIdLong and another element has the expected objFKeyString you could combine the accessors.
Something like this:
.andExpect(jsonPath('$.id[?(#.objIdLong == 533252 && #.objFKeyString == \'SomeString\')]').exists())
.andExpect(jsonPath('$.id[?(#.objIdLong == 642654252 && #.objFKeyString == \'ThisString\')]').exists())
.andExpect(jsonPath('$.id[?(#.objIdLong == 4624352 && #.objFKeyString == \'SomeOtherString\')]').exists())
These assertions will be deemed true as long as the returned JSON contains:
An id sub document with objIdLong=533252 and objFKeyString="SomeString"
An id sub document with objIdLong=642654252 and objFKeyString="ThisString"
An id sub document with objIdLong=4624352 and objFKeyString="SomeOtherString"
At the time of writing there was an easier way of doing it .andExpect(content().json(expected_response))
.json(expected_response) validation has an option to do a strict or a lenient checking. This is helpful for arrays where you do not care about response ordering which can change. If you want to turn strict checking it on you can turn it on like .json(expected_response,true) . Also you can load your whole response from a file reader and do a direct assert without having to tediously write json path. Here is a complete example.
#Test
#DisplayName("invalid fields")
void invalidfields() throws Exception {
String request = getResourceFileAsString("test-data/http-request/invalid-fields.json");
String response_file_path = "test-data/http-response/error-messages/invalid-fields.json";
String expected_response = getResourceFileAsString(response_file_path);
mockMvc.perform(evaluateRulesOnData(TRACKING_ID.toString(), request))
.andExpect(status().isBadRequest())
.andExpect(content().json(expected_response));
}
helper function to load test files from classpath
public static String getResourceFileAsString(String fileName) throws IOException {
Resource resource = new ClassPathResource(fileName);
File file = resource.getFile();
return new String(Files.readAllBytes(file.toPath()));
}
The expected response has an array with many elements in the list which are matched despite being in random order during each test run.
I am new to groovy and soapui pro. I have below sample response that displays 2 or more array elements with dynamic data. I am wondering how to write a script assertion or xpath match to check if script passes as long as one of the elements has value 1.
<ns1:SampleTests>
<ns1:SampleTest1>
<ns1:Test>1</ns1:Test>
</ns1:SampleTest1>
<ns1:SampleTest2>
<ns1:Test>2</ns1:Test>
</ns1:SampleTest2>
</ns1:SampleTests>
I have written this in script assertion but its failing.
Supposing that you've a response like:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ns1:SampleTests xmlns:ns1="hola">
<ns1:SampleTest1>
<ns1:Test>1</ns1:Test>
</ns1:SampleTest1>
<ns1:SampleTest2>
<ns1:Test>2</ns1:Test>
</ns1:SampleTest2>
</ns1:SampleTests>
</Body>
</Envelope>
You can perform the follow XPath: exists(//*:Test[.=1]) to check that exists at least one <ns1:Test> element with 1 as value.
Inside an XPath Match it looks like:
If instead you prefer to use an Script assertion you can use the XmlSlurper to parse your Xml, then get all <ns1:Test> values an assert that at least one has 1 as value. Look into the follow code:
// get the response
def responseStr = messageExchange.getResponseContent()
// parse the response as slurper
def response = new XmlSlurper().parseText(responseStr)
// get all <ns1:Test> values
def results = response.'**'.findAll { it.name() == 'Test' }
// now in results list we've NodeChild class instances we will convert it to
// string in order to perform the assert
results = results.collect { it.toString() }
// check that at least one element has '1' value
assert results.contains('1'),'RESPONSE NOT CONTAINS ANY <ns1:Test>1</ns1:Test>'
I am trying to build a mock service in SoapUI, which dynamically returns a response, based on a value passed in the request. Example:
<foo>
<bar>
<ID>Response1</ID> <--- I want to extract this
<ReferenceID>stuff</ReferenceID>
<CreationDate>2016-05-01T11:34:56Z</CreationDate>
</bar>
</foo>
So I set my DISPATCH to SCRIPT and tried the following (the return value should specify the name of the response, which is returned):
def req = new XmlSlurper().parseText(mockRequest.requestContent)
return "${req.foo.bar.ID}"
And this:
def holder = new com.eviware.soapui.support.XmlHolder(mockRequest.requestContent )
def arg1 = holder.getNodeValue("ID") // also tried "//ID"
return arg1.toString();
Neither worked, the mock always returns the default response - hope some of you can help me with the solution :)
The problem is probably that your <foo> response is wrapped in a SOAP<envelope> and <body> so the path you're using with XmlSlurper is not correct req.foo.bar.ID.
Furthermore if in your case your response is not wrapper with <envelope> and <body> note that in the XmlSlurper the root node starts at the object itself so the req.foo is not needed since <foo> is the root node, looks at the follow example:
def xml =
'''<foo>
<bar>
<ID>Response1</ID>
<ReferenceID>stuff</ReferenceID>
<CreationDate>2016-05-01T11:34:56Z</CreationDate>
</bar>
</foo>
'''
def slurper = new XmlSlurper().parseText(xml)
println slurper.foo // prints nothing...
println slurper.bar.ID // prints Response1
Due to this maybe the easy way to get the node value is to use find method, so in your DISPATCH script:
def req = new XmlSlurper().parseText(mockRequest.requestContent)
return req.'**'.find { it.name() == 'ID' }
Alternatively if you want to use XmlHolder instead of XmlSlurper as #Rao comments simply use a namespace on your XPath. Fortunately SOAPUI allows you to use * as a wildcard for namespaces so correct ID by //*:ID:
def holder = new com.eviware.soapui.support.XmlHolder(mockRequest.requestContent )
return holder.getNodeValue("//*:ID").toString()
Hope it helps,