I am new to Groovy Scripting. I am trying to access the value of a Response node
below is the script
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def responseHolder = groovyUtils.getXmlHolder( testRunner.testCase.testSteps["request"].testRequest.response.responseContent );
responseHolder.namespaces["ns0"]="http://xmlns.int.com/orders/xsd/v1"
String mySection = responseHolder.getNodeValue["//ns0:MT_OrderCreateDTCFulfillmentResponse/ns0:StatusCode"] ;
log.info mySection
mySection is printed as []
Response XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:v1="http://xmlns.int.com/orders/xsd/v1"/>
<soapenv:Body xmlns:v1="http://xmlns.int.com/orders/xsd/v1">
<ns0:MT_OrderCreateDTCFulfillmentResponse xmlns:ns0="http://xmlns.int.com/orders/xsd/v1">
<StatusCode>000</StatusCode>
<ReferenceDocNbr>NA</ReferenceDocNbr>
<SchemaValidationStatus>Validated</SchemaValidationStatus>
<StatusTimestamp>2015-08-03T18:58:01.602</StatusTimestamp>
<FaultDetails>Request for customer order number NA received successfully and format validated.</FaultDetails>
</ns0:MT_OrderCreateDTCFulfillmentResponse>
</soapenv:Body>
</soapenv:Envelope>
SOAP UI Project Structure - I am running Test_Script. Suggest me what i am missing
You've to use:
responseHolder.getNodeValue("//ns0:MT_OrderCreateDTCFulfillmentResponse/StatusCode");
instead of responseHolder.getNodeValue["//ns0:MT_OrderCreateDTCFulfillmentResponse/ns0:StatusCode"];
Note that I change responseHolder.getNodeValue invocation to use () instead of [], and also change your xpath since in your response <StatusCode> it's not defined in xmlns:ns0="http://xmlns.int.com/orders/xsd/v1".
Another option is to use the * wildcard as a namespace to map anyone. So in this case you can use:
responseHolder.getNodeValue("//*:MT_OrderCreateDTCFulfillmentResponse/*:StatusCode");
Additionally, note that probably you XML is wrong, since I suppose that all sub elements of <MT_OrderCreateDTCFulfillmentResponse> must belongs to "http://xmlns.int.com/orders/xsd/v1" namespace... so you've to declare it as:
<ns0:MT_OrderCreateDTCFulfillmentResponse xmlns:ns0="http://xmlns.int.com/orders/xsd/v1">
<ns0:StatusCode>000</ns0:StatusCode>
<ns0:ReferenceDocNbr>NA</ns0:ReferenceDocNbr>
<ns0:SchemaValidationStatus>Validated</ns0:SchemaValidationStatus>
<ns0:StatusTimestamp>2015-08-03T18:58:01.602</ns0:StatusTimestamp>
<ns0:FaultDetails>Request for customer order number NA received successfully and format validated.</ns0:FaultDetails>
</ns0:MT_OrderCreateDTCFulfillmentResponse>
Or using as default for this tag:
<MT_OrderCreateDTCFulfillmentResponse xmlns="http://xmlns.int.com/orders/xsd/v1">
<StatusCode>000</StatusCode>
<ReferenceDocNbr>NA</ReferenceDocNbr>
<SchemaValidationStatus>Validated</SchemaValidationStatus>
<StatusTimestamp>2015-08-03T18:58:01.602</StatusTimestamp>
<FaultDetails>Request for customer order number NA received successfully and format validated.</FaultDetails>
</MT_OrderCreateDTCFulfillmentResponse>
Note that if you change you XML with my indication your first XPath it's correct since now StatusCode belongs to your namespace.
Hope it helps,
Related
I have a spreadsheet where each row contains a SOAP request, concatenated from the data in that row. So cell G2 is a SOAP request, cell G3 is a different SOAP request, cell G4 is another SOAP request and so on. I've looked to see what is the best method for transferring those 100+ SOAP requests into SoapUI (free version) and running them all in one batch. I've not found anything that gives me the full working solution yet. Could someone suggest the best method please? Thanks in advance!
I won't tell you how to do it, but I can tell you how I did it. Concatenating XML in Excel is messy and error-prone, especialy if you have less-technical people writing the test cases. I asked for the data (parameters) in Excel.
I wrote a Groovy script that gets the data (there's a nice script that abstracts it for you), and for each test case, saved the values as properties:
new ExcelBuilder("data/MyRegressionSheetV1.2.xls").eachLine([labels:true]) { row ->
Map payLoad = [:]
if (cell(0)) {
payLoad['MyName'] = cell(0)
payLoad['MySurname'] = cell(1)
//and so on
payLoad['ExpectedResult'] = cell(12)
testRunner.testCase.testSuite.project.setPropertyValue("Name", payLoad['MyName'])
testRunner.testCase.testSuite.project.setPropertyValue("Surname", payLoad['MySurname'])
//and so on
def MyScenario = testRunner.testCase.testSuite.testCases["SOAP Request1"].run( null, true )
then made the SOAP requests with parameterised values:
<parm:Name>${#Project#Name}</parm:Name>
<parm:Surname>${#Project#Surname}</parm:Surname>
//and so on
While in the loop, you can get the response values and if you have expected results, you can compare them programmatically:
def responseSOAP = context.expand('${SOAP Request1#Response}')
def responseSection = responseSOAP =~ /requestAnswer>(.*)<\/requestAnswer/
def response = responseSection[0][1]
if (response.equals(payLoad['ExpectedResult'])) {
testResult = 'Pass'
}
}
Opensource SoapUI is very capable, and Groovy is a very cool programming language. A lot is possible once you get your head around how they work together.
EDIT:
If you want to replace the entire request, you can access it with the XmlHolder:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
//this gets a handle on the current request XML
def oldHolder = groovyUtils.getXmlHolder( 'SOAP Request1#Request' )
//your String XML from the spreadsheet must be parsed into XML
def newHolder = new XmlSlurper().parseText(MyXMLFromSheetAsString)
//replace
context.requestContent = newHolder.xml
I'm using SoapUi 5.3.0 to test a case like this:
I have 3 apis: Book list, Add a book to favorite list, and Favorite list.
I add 3 apis to a TestCase as TestSteps to test the case: User views book list, choose the first book in the list then adds to favorite list, after that user goes to favorite list to verify that the book is displayed in the first place in Favorite list.
I add a propertyTransfer between step 1 and step 2, to get book_id from respond of step 1, then use to a param of the next step's request.
At step 3, I add an assertion by Script Assertion like below:
import groovy.json.JsonSlurper
//get propertyTransfer value
def tcProperty = messageExchange.modelItem.testStep.testCase.getTestStepByName("propertyTransfer").getPropertyValue("book_id")
// get response message of Favorite book api
def responseMessage = messageExchange.response.responseContent
// get book_id of the first book in favorite list
def jsonSlurper = new JsonSlurper().parseText(responseMessage)
bookId = jsonSlurper.data[0].book_id
// verify
assert bookId == tcProperty
But the script returns failed, and an error displays like attach photo
It seems tcProperty is null, means I could not get propertyTransfer value.
So where am I wrong?
You can either use Property Transfer test step or without it i.e., using Script Assertion for the request step itself.
If Script Assertion is used, then Property Transfer step is not needed at all.
The idea is extract the required value, and set it at test case level custom property in the Script Assertion.
Now, you want to use the above extracted value in the next step, which can be done using property expansion.
Here is the script assertion:
//Check if the response is not empty
assert context.response, 'Response is empty or null'
def jsonSlurper = new groovy.json.JsonSlurper().parseText(context.response)
bookId = jsonSlurper.data[0].book_id
assert bookId, 'Book id is empty or null'
//Set the bookId as test case level property
context.testCase.setPropertyValue('BOOK_ID', bookId)
In the next step, use property expansion i.e., ${#TestCase#BOOK_ID} where ever you needed book id
I am trying to transfer the response from one test case to another in SOAPUI. So that i can search by country and retrieve the currency code to use then search by currency code. However i am not sure i am getting my xpath correct.
SOAP WSDL used: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL
This is a practice for a service which is shortly due to be delivered.
Initial test case post
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.webserviceX.NET">
<soap:Header/>
<soap:Body>
<web:GetCurrencyByCountry>
<!--Optional:-->
<web:CountryName>Belgium</web:CountryName>
</web:GetCurrencyByCountry>
</soap:Body>
</soap:Envelope>
Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCurrencyByCountryResponse xmlns="http://www.webserviceX.NET">
<GetCurrencyByCountryResult><![CDATA[<NewDataSet>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
</NewDataSet>]]></GetCurrencyByCountryResult>
</GetCurrencyByCountryResponse>
</soap:Body>
</soap:Envelope>
I am then using the property transfer test step, Firstly setting the drop downs as follows:
Source: Get Currency by Country; Property: Response Path Language: xpath
Then declared the xpath as follows:
declare namespace sam= 'http://www.webserviceX.NET';//GetCurrencyByCountryResult/table[2]/CurrencyCode
Each time i run the test i get a Null response. I have attempted using a wild card however i still cannot pick up the value.
Here is the groovy script which does exactly what you are looking for:
Added comments appropriately before each statement for better understanding.
Currently using the fixed xml response. But you may replace it to make it dynamic.
Since your xml has cdata and cdata has xml again. So, this needs to be done in two phases, first time cdata and then xpath to get the actual value that is needed.
import com.eviware.soapui.support.XmlHolder
def xml = '''<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body>
<GetCurrencyByCountryResponse xmlns="http://www.webserviceX.NET">
<GetCurrencyByCountryResult><![CDATA[<NewDataSet>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
</NewDataSet>]]></GetCurrencyByCountryResult>
</GetCurrencyByCountryResponse>
</soap:Body>
</soap:Envelope>'''
//If you want this script to handle dynamic response
// remove above xml and uncomment below line and replace your previous step name in
// place of STEP_NAME
//def xml = context.expand( '${STEP_NAME#Response}' )
//Please replace the actual response in place of xml
def holder = new XmlHolder(xml)
//Get the CDATA part
def countryCodeResult = holder.getNodeValue('//*:GetCurrencyByCountryResult')
//log the content of CDATA
log.info countryCodeResult
//Again convert cdata string as xml holder
def cdataHolder = new XmlHolder(countryCodeResult)
//Get the actual xpath
def currencyCode = cdataHolder.getNodeValue("//Table[2]/CurrencyCode")
log.info currencyCode
//now you may store this currency code as suite level propery so that
//you can use it in next test case as ${#TestSuite#CURRENCY_CODE}
context.testCase.testSuite.setPropertyValue('CURRENCY_CODE', currencyCode)
As you see in the above comment, the script is storing currency code into a test suite level property. That allows you to use the currency code in different test case or step using property expansion, say ${#TestSuite#CURRENCY_CODE}
You need to store the CDATA Content in to a property and then use that property value in groovy script and access CDATA internal xml, I am referring in the below example <![CDATA[<isle>test</isle>]]> .
eg:
<test>
<elementa>
<![CDATA[<isle>test</isle>]]>
</elementa>
</test>
In your current scenario Soapui only understand XPATH up to "//GetCurrencyByCountryResult" , after that whatever path have provided goes under CDATA .
SOAPUI working with CDATA is separate mechanism.
Please look into this; it has lot of information on CDATA with SOAPUI and its definitely solve your issue
https://www.soapui.org/functional-testing/working-with-cdata.html
I am trying to use using script assertion or by groovy code to check if a value under an element in xml response exits in particular format.
Sample response :
<ns5:price>99.99</ns5:price>
<ns5:date>2016-04-04</ns5:date>
<ns5:quantity>1</ns5:quantity>
For example, I want to check if any price exists and in format 5,4, same for date to see if date in format yyyy-mm-dd and quantity is not 0.
All the values are dynamic.
I am wondering if we can use using a script assertion or can use point and click with soap ui pro.
I am just learning soapui pro and groovy.
Thanks.
You can create an script assertion in your SOAP testStep and make the validations there. In the script assertion you can parse the response using a XmlSlurper, then get the desired nodes using findAll and perform all the asserts. You can do it using something like:
// from script assertion get the response
def response = messageExchange.getResponseContent()
// parse the XML
def xml = new XmlSlurper().parseText(response)
// get all prices
def prices = xml.'**'.findAll { it.name() == 'price' }
// check that each one has at "max 5 digits.max 4 digits"
prices.each { assert it ==~ /\d{0,5}\.\d{0,4}/ }
// get all dates
def date = xml.'**'.findAll { it.name() == 'date' }
// check the date has yyyy-MM-dd format
date.each { assert it ==~ /\d{4}\-\d{2}\-\d{2}/ }
// get all quantities
def quantity = xml.'**'.findAll { it.name() == 'quantity' }
// check that all quantities are > 0
quantity.each { assert it.text().toInteger() > 0 }
NOTE: To add an script assertion to your request, click on Assertions tab on left down corner of your SOAP Request panel:
Then right click on it and select add Assertion:
In a new panel select Script from a left side menu and then Script Assertion on the right options:
Finally use the code provided and make your checks :):
How can I get the value of any tag (e.g. Quantity) from the below XML by passing the tag name without using hard coded tag name-
def temp1="""
<TradeRecord>
<TradeId>1000</TradeId>
<SecurityId>10382456</SecurityId>
<TradeType>SELLL</TradeType>
<TradeDate>2014-03-21</TradeDate>
<Broker>100</Broker>
<Exchange>1</Exchange>
<Status>INIT</Status>
<Quantity>125</Quantity>
<ApprovedBy />
</TradeRecord>
"""
def records = new XmlParser().parseText(temp1)
//log.info records.Quantity[0].text() By using this i am getting value but i want 'Quantity' to come from a string
tag = 'Quantity'
xy = records["Quantity"].value; 'This is not working
log.info xy
You should be able to do
records."$tag".text()
You should have used .text() method
records[tag].text()