Trouble using XmlParser in SoapUI Pro
Hi, I am trying to use 'xml parser' to validate my xml responses in SoapUI Pro.
I have been playing around with this in a groovy script and I can access the tags if I declare and assign my xml within the groovy script like so
This works if I declare the xml in the script ..
def xml = """
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration /core/V1">2013-12-24T22:20:34</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:completedShipmentInfo>
//xml not complete, other info in here.
</NS1:completedShipmentInfo>
<NS1:integrationFooter>
<warnings xmlns="http://www.royalmailgroup.com/integration/core/V1">
<warning>
<warningCode>W0022</warningCode>
<warningDescription>The customerReference specified is longer than 12 characters and has been truncated</warningDescription>
</warning>
<warning>
<warningCode>W0026</warningCode>
<warningDescription>The departmentReference specified is invalid and will be ignored</warningDescription>
</warning>
</warnings>
</NS1:integrationFooter>
</NS1:createShipmentResponse>
"""
def parser = new XmlParser().parseText(xml)
parser.'NS1:integrationFooter'.warnings.warning.warningCode.each{
log.info it.text()
}
But it doesn't seem to work within a running test instance when I instantiate the xmlParser variable from my Soap response as below.
def response = context.expand( '${createShipment_v04#Response}' );
I know that the parser variable has been assigned the xml response because when I can print it to the log ..
i.e. log.info parser prints ...
Wed Jan 08 16:33:38 GMT 2014:INFO:{http://schemas.xmlsoap.org/soap/envelope /}Envelope[attributes={}; value=[{http://schemas.xmlsoap.org/soap/envelope/}Body[attributes={}; value=[{http://www.royalmailgroup.com/api/ship/V1}createShipmentResponse[attributes={}; value=[{http://www.royalmailgroup.com/api/ship/V1}integrationHeader[attributes={}; .......
But below code does not print anything when I instantiate the xmlParser request from the soap response.
parser.'NS1:integrationFooter'.warnings.warning.warningCode.each{
log.info it.text()
}
Any help would be much appreciated.
I believe you are working at the wrong level.
parser.Body….
Ok. It turns out I don't need the 'NS1:' part. The below works ..
slurper.Body.createShipmentResponse.integrationFooter.warnings.warning.warningCode.each{
log.info it.text()
}
Following should work:
def response = context.expand( '${createShipment_v04#Response}' );
def parser = new XmlSlurper().parseText(response)
def warningCodes = parser.'**'.findAll {
it.name()=='warningCode'
}
warningCodes.each {
log.info it
}
Related
Hello I'm new to this Groovy Script thing in SOAP UI can anyone tell me what i'm doing wrong? i can't do a if null condition with this code
//Getting Request
def RequestMessage=context.request
log.info RequestMessage
def jsonSlurper = new JsonSlurper().parseText(RequestMessage)
try{
if(jsonSlurper.iso8583Request.iso8583Detail.bit127){
log.info "127 is null"
}else{
testRunner.testCase.setPropertyValue("revBit127", "${jsonSlurper.iso8583Request.iso8583Detail.bit127}")
}catch{
log.info "127 is null"
}
Any advice to handle if null condition from this Json object?
You're not far off.
Firstly, I don't chain when using JSON Slurper, I tend to use it like this...
import groovy.json.JsonSlurper;
def response = context.expand( '${SOME REST Request#Response#$[\'message\']}' )
// Create a slurper object.
def slurper = new groovy.json.JsonSlurper();
// Create the JSON
def json = slurper.parseText(response);
In your example, I think this is wrong...
if(jsonSlurper.iso8583Request.iso8583Detail.bit127){
log.info "127 is null"
You're actually checking it exists, instead try...
if(!jsonSlurper.iso8583Request.iso8583Detail.bit127){
log.info "127 is null"
}else{
testRunner.testCase.setPropertyValue("revBit127", "${jsonSlurper.iso8583Request.iso8583Detail.bit127}")
}
I'd like to make assert to check that data which I sent by REST request with json is equal to item from test case properties. I dont know how to deliver it from test request properties.
Initialy I am traying wrote script assertion like below, but probbaly getProperty doesnt work:
import groovy.json.JsonSlurper
def responseMessage = messageExchange.response.responseContent
def json = new JsonSlurper().parseText(responseMessage)
assert json.items[0].agreementTypeID == testRunner.testCase.getPropertyValue('agreementTypeID').toInteger()
// Script assertion only context will work
log.info context.testCase.getPropertyValue("agreementTypeID")
// Script assertion testrunner will not work
log.info testRunner.testCase.getPropertyValue('agreementTypeID')
So if you replace the testRunner with context it should work in Script Assertion .
TestRunner is available in Groovy step and there is a special way of making testRunner available in Script Assertion , but above is better
I am writing my first Groovy script, where I am calling a REST API.
I have the following call:
def client = new RESTClient( 'http://myServer:9000/api/resources/?format=json' )
That returns:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
I am trying to get the field level, like this:
def level_value = client.get( path : 'msr/data/level' )
However, when I print the value of the variable obtained:
println level_value.getData()
I get the whole JSON object instead of the field:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
So, what am I doing wrong?
Haven't looked at the docs for RESTClient but like Tim notes you seem to have a bit of a confusion around the rest client instance vs the respons object vs the json data. Something along the lines of:
def client = new RESTClient('http://myServer:9000/api/resources/?format=json')
def response = client.get(path: 'msr/data/level')
def level = response.data[0].msr[0].data.level
might get you your value. The main point here is that client is an instance of RESTClient, response is a response object representing the http response from the server, and response.data contains the parsed json payload in the response.
You would need to experiment with the expression on the last line to pull out the 'level' value.
I am trying to hold the response of my request in a holder variable but I am not able to.
In SoapUI groovyutils is in-built and can be used easily. But I am sending my soap request using groovy and it is working fine. Now I want to get the response in a holder and put some assertions.
My piece of code for this is :
import com.eviware.soapui.*
def groovyUtils = new com.eviware.soapui.support.GroovyUtils()
def responseHolder = groovyUtils.getXmlHolder( messageExchange.responseContent )
Here I am not able to get as how I should pass the context in groovyutils and what all classes to call.
I'm not sure that I fully understand your problem, however seems that you want to check a SOAP response out of SOAPUI but using the facilities from SOAPUI jar isn't it?
If you want simply perform some assert in the response, then I would recommend you to avoid the use of GroovyUtils. Simply use XmlSlurper to parse the response, then get the desired values from the xml nodes and perform your asserts.
Since your Groovy code to you invoke the service and the response is missing I simply show you a possible example using XmlSlurper:
def response = '''<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/">
<soap:Body>
<myResponse>
<someNode>myText</someNode>
</myResponse>
</soap:Body>
</soap:Envelope>'''
def xml = new XmlSlurper().parseText(response)
// find the <someNode> element
def someNode = xml.'**'.find { it.name() == 'someNode' }
// check that the <someNode> has a value equals of 'myText'
assert someNode.text() == 'myText'
Hope it helps,
I am new to SoapUI and Groovy so please forgive this post as it has been posted a number of times in Stackoverflow however I cannot find a fix.
SoapUI version: 4.5.2
I have 2 questions if you guys don't mind:
I have an executable jar file that I've put in the the \bin\ext directory along with another jar that is considered a dependency jar within the code in the jar so I hope it will reference there. The groovy code I found in Stackoverflow that should execute this jar is as follows but does not work as I don't see any output anywhere in the SoapUI directory.
Here is the code:
def command = "java -jar UpdateAppIdXMLRequest.jar file.xml"
def process = command.execute()
process.waitFor()
def output = process.in.text
log.info output
This jar creates 25 xml files that should be able to be picked up by the SoapUI and put them in as TestSteps in the same project. In my java code in what path do I put these files?
Here is the code in my jar:
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
class UpdateAppIdXMLRequest {
static main(args) {
try {
SAXBuilder builder = new SAXBuilder();
File xmlFile = new File("c:\\file.xml");
Document doc = (Document) builder.build(xmlFile);
Element rootNode = doc.getRootElement();
// Create loop to create 25 testStepApps
for (int i = 1; i < 26; i++) {
// Get current AppID, incrementAppID and update the ApplicationNumber attribute value for next test script.
int appID = Integer.parseInt(rootNode.getAttributeValue("ApplicationNumber"));
appID++;
String appIDValue = Integer.toString(appID);
rootNode.getAttribute("ApplicationNumber").setValue(appIDValue);
XMLOutputter xmlOutput = new XMLOutputter();
// Create new XML file with next AppID
xmlOutput.setFormat(Format.getPrettyFormat());
xmlOutput.output(doc, new FileWriter("c:\\testStepApp" + i + ".xml"));
// xmlOutput.output(doc, System.out);
// System.out.println("File updated!");
}
} catch (IOException io) {
io.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
}
Any help/direction would be appreciated.
Thanks.
In order to do so, I recommend that you use directly groovy test step instead of a jar, this way you have more flexibility an you have not recompile the jar each time you must need to change something.
So, in order to achieve your goal, at first you need to create a TestCase inside your project, create a SOAP Test Step and Groovy Test Step inside like this:
I will use SOAP Test Step to create the other test steps (to create test steps it needs the wsdl:operation and so on, and it's more easy to copy the test step that create directly).
In the Groovy Test Step I will put the necessary code to do the work which is showed below:
import com.eviware.soapui.support.XmlHolder
import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestRequestStepFactory
// read your request template
def requestFile = new File("C:/file.xml");
// parse it as xml
def requestXml = new XmlHolder(requestFile.text)
// get the current testCase to add testSteps later
def tc = testRunner.testCase;
// get the testStep as template to create the other requests
def tsTemplate = tc.getTestStepByName("Template");
// loop to create 25 testStep
for(int i = 1; i < 26; i++){
// xpath expression to get applicationNumber attribute in root node
def xpathNodeAttr = "/*/#ApplicationNumber";
// get the root node attribute applicationNumber throught an XPATH
int appId = Integer.parseInt(requestXml.getNodeValue(xpathNodeAttr));
// add 1 to appId
appId++;
// set the value again in the attribute
requestXml.setNodeValue(xpathNodeAttr,appId);
def testStepName = "TestStep_ApplicationNumber_"+ String.valueOf(appId)
log.info testStepName;
log.info testStepName.getClass().getName()
log.info tc.getClass().getName()
// create a new testStepConfig
def testStepFactory = new WsdlTestRequestStepFactory();
def testStepConfig = testStepFactory.createConfig( tsTemplate.getOperation(), testStepName )
// add the new testStep to TestCase
def newTestStep = tc.insertTestStep( testStepConfig, -1 )
// set the request which just create
newTestStep.getTestRequest().setRequestContent(requestXml.getXml())
}
This code it's basically your java code "translated" to groovy and added the necessary code to create the test steps. In a few words this code reads a request from a file, and create 25 test steps in the current test case using the request, in each request it only changes the ApplicationNumber attribute of the root node adding it +1.
EDIT BASED ON COMMENT:
If you use a REST Request step instead of SOAP Request Step you have to change a bit your groovy code to use com.eviware.soapui.impl.wsdl.teststeps.registry.RestRequestStepFactory and getTestRequest() method on it. So if you have a REST Service with a POST method create a Test Case with a REST Request test step and Groovy Test Step like this:
And use this groovy code instead, basically this code it's the same and works like the code above and makes the same thing with REST Request instead of SOAP Request:
import com.eviware.soapui.support.XmlHolder
import com.eviware.soapui.impl.wsdl.teststeps.registry.RestRequestStepFactory
// read your request template
def requestFile = new File("C:/file.xml");
// parse it as xml
def requestXml = new XmlHolder(requestFile.text)
// get the current testCase to add testSteps later
def tc = testRunner.testCase;
// get the testStep as template to create the other requests
def tsTemplate = tc.getTestStepByName("Template");
// loop to create 25 testStep
for(int i = 1; i < 26; i++){
// xpath expression to get applicationNumber attribute in root node
def xpathNodeAttr = "/*/#ApplicationNumber";
// get the root node attribute applicationNumber throught an XPATH
int appId = Integer.parseInt(requestXml.getNodeValue(xpathNodeAttr));
// add 1 to appId
appId++;
// set the value again in the attribute
requestXml.setNodeValue(xpathNodeAttr,appId);
def testStepName = "TestStep_ApplicationNumber_"+ String.valueOf(appId)
log.info testStepName;
log.info testStepName.getClass().getName()
log.info tc.getClass().getName()
// create a new testStepConfig
def testStepFactory = new RestRequestStepFactory();
def testStepConfig = testStepFactory.createConfig( tsTemplate.getTestRequest(), testStepName )
// add the new testStep to TestCase
def newTestStep = tc.insertTestStep( testStepConfig, -1 )
// set the request which just create
newTestStep.getTestRequest().setRequestContent(requestXml.getXml())
}
Hope this helps.