I wrote a groovy script in soapui to create files in certain location in my pc. How can I make it dynamic and enable the user to write the location the files are saved to by write the location in configuration file imported at test suite level.
if(context.expand('${#Project#ProduceReports}') == 'true') {
def resultDir = new File("D:\\Reports");
if(!resultDir.exists()) {
resultDir.mkdirs();
}
def resultsFile = new File(resultDir, "CSVReport.csv");
}
If you want to get the path from a testSuite property, you can do it as you do with the project property, using context.expand:
def yourPath = context.expand('${#TestSuite#pathDirectory}')
Or alternatively you can do the same with:
def yourPath = context.testCase.testSuite.getPropertyValue('pathDirectory')
Maybe this is out of scope for your question, but could be helpful. If you need you can also use UISupport to ask the user to enter the path he wants with the follow code:
def ui = com.eviware.soapui.support.UISupport;
// the prompt question, title, and default value
def path = ui.prompt("Enter the path","Title","/base/path");
log.info path
This shows:
Define project level custom property REPORT_PATH with value D:/Reports/CSVReport.csv i.e., full path including file and path separate by / slash even on windows platform.
Then use the below script to write the data.
//Define the content that goes as report file. Of course, you may change the content as need by you
def content = """Name,Result
Test1,passed
Test2,failed"""
//Read the project property where path is configured
def reportFileName = context.expand('${#Project#REPORT_PATH}')
//Create file object for reports
def reportFile = new File(reportFileName)
//Create parent directories if does not exists
if (!reportFile.parentFile.exists()) {
reportFile.parentFile.mkdirs()
}
//Write the content into file
reportFile.write(content)
Related
May I know how to print the directory path which is 1 level up? (eg. the groovy file is located in "abc/def/ghi/dummy.groovy" and I want to get the "abc/def" path)
here is my dummy.groovy script
File fileCon= new File("/../")
logger.debug((String.format("[%s]", fileCon))
groovy file could be loaded from plain file, from jar, from url.
i'd not recommend to use this approach - it will not work for all cases.
def url = this.getClass().getProtectionDomain().getCodeSource()?.getLocation()
println new URL(url, '..')
Here is how you get the parent directory as File:
def file = new File('abc/def/ghi/dummy.groovy')
println "Parent: ${file.getParentFile().absolutePath}"
it will give you abc/def/ghi/. You may get parent folder from the result:
println "Parent: ${file.getParentFile().getParentFile().absolutePath}"
you'll get your desired abc/def.
I didn't see any File in GroovyDocs, so I presume this is a Java Class.
So why not just use:
def file = new File('abc/def/ghi/dummy.groovy')
def filePath = file.getParent().getParent()
In extension to this question.
Is it possible to read a file into a string without knowing the path to the file? - I only have the file as a 'def'/type-less parameter, which is why I can't just do a .getAbsolutePath()
To elaborate on this, this is how I import the file (which is from a temporary .jar file)
def getExportInfo(path) {
def zipFile = new java.util.zip.ZipFile(new File(path))
zipFile.entries().each { entry ->
def name = entry.name
if (!entry.directory && name == "ExportInfo") {
return entry
}
}
}
A ZipEntry is not a file, but a ZipEntry.
Those have almost nothing in common.
With def is = zipFile.getInputStream(entry) you get the input stream to the zip entry contents.
Then you can use is.text to get the contents as String in the default platform encoding or is.getText('<theFilesEncoding>') to get the contents as String in the specified encoding, exactly the same as you can do on a File object.
I want to save soap test step raw request & step in a path which is read from configuration file imported in test suite custom properties.
How can I do that?
Using the below script but with fixed location that was defined in the script.
def myOutFile = "D:/TestLog/Online_Test/PostPaidSuccess_Payment_BillInqReq.xml"
def response = context.expand( '${BillInq#Request}' )
def f = new File(myOutFile)
f.write(response, "UTF-8")
I would suggest to avoid additional Groovy Script test step to just store previous step request / response.
Below script assumes that, there is user defined property (REQUEST_PATH) at test suite level with its value(valid file path to store data, path separated by forward slash '/' even on windows).
Instead use Script Assertion for the Billing request step itself(one more step less in the test case)
//Stores raw request to given location using utf-8 encoding
new File(context.testCase.testSuite.getPropertyValue('REQUEST_PATH') as String).write(context.rawRequest,'utf-8')
Actually there is a small difference between context.request and context.rawRequest and the above script using rawRequest.
context.request - will have the variables as it is, not the actual value.
For eg:
<element>${java.util.UUID.randomUUID().toString()}</element>
Where as context.rawRequest - will have the actual value that was sent in the request.
For eg:
<element>4ee36185-9bfb-47d2-883e-65bf6d3d616b</element>
EDIT Based on comments: Please try this for ACCESS DENIED issue
def file = new File(context.testCase.testSuite.getPropertyValue('REQUEST_PATH') as String)
if (!file.canWrite()) {
file.writable = true
}
file.write(context.rawRequest,'utf-8')
EDIT2 Based on further comments from OP, the request file name should be the current test step name.
//Create filename by concatenating path from suite property and current test stepname
def filename = "${context.testCase.testSuite.getPropertyValue('REQUEST_PATH')}/${context.currentStep.name}.xml" as String
new File(filename).write(context.rawRequest,'utf-8')
I don't know hardly anything about XML. I have successfully gotten a SOAP response (using things like SOAPUi and Boomerang) from an asmx web service. It's a large file.
Now I need to get it to regular delimited columns. Is there a simple way to do this?
My file is attached here
Not sure if it is required one time transformation or do this job quite frequently.
So, adding the answer here with some more details.
Approach #1: Using on-line
As mentioned in the comments, you can use the on-line site to convert your xml data into csv.
Even it requires to do some pre-process with the message / response that you have i.e.,
save the data into file
remove headers or unwanted data etc or make it ready to be usable in the above mentioned online site.
The disadvantages in this approaches
requires some manual work
expose data on public, but at times may be possible to share
time taking
can not use it an automated fashion
difficult to repeat
Approach #2: Using Groovy Script
So, this approach addresses the disadvantages of #1 approach.
Here is the Groovy Script which reads previous soap request step's response, and gives the data into a csv file.
In your test case, add a new groovy script test step right after the soap request step which gives you the data and copy below script content into it. i.e., (Test Case -> Step 1: Soap Request where you are getting responseStep 2: Groovy Script (with below script))
Add a test case custom property, say OUTPUT_FILE_NAME and provide the file path for csv to be saved at. Even, if you do not provide this property, it will automatically saves the csv file chargedata.csv under System temp directory.
You may find the comments in-line
/**
* this script will read the previous step response
* extract the cdata at the given xpath
* read all the records and transfroms into csv file
**/
import com.eviware.soapui.support.XmlHolder
import groovy.xml.*
/**Define the output file name in test case custom property say OUTPUT_FILE_NAME and value as absolute file path
* otherwise, it write a file chargedata.csv in system temp directory
**/
def outputFileName = context.testCase.getPropertyValue('OUTPUT_FILE_NAME') ?: System.getProperty("java.io.tmpdir")+ '/chargedata.csv'
//csv field separator - change it if needed
def delimiter = ','
/**
* Below statement will fetch the previous request step response.
*/
def response = context.testCase.testStepList[context.currentStepIndex - 1].testRequest.response.responseContent
//Create the xml holder object to get the xpath value which cdata in this case
def responseHolder = new XmlHolder(response)
def xpath = '//*:Charges_FileResponse/*:Charges_FileResult'
//Get the cdata part from above xpath which is a string
def data = responseHolder.getNodeValue(xpath)
//This again parses the xml inside of cdata
def chargeRecords = new XmlParser().parseText(data)
//This is going hold all the data from ChargeRecords
def chargeRecordsDataStructure = []
//This is to hold all the headers
def headers = [] as Set
/**
* This is to create Charge data
**/
def buildChargeDataStructure = { charge ->
def chargeDataStructure = new Expando()
charge.children().each {
def elementName = it.name()
def elementText = it.value().join()
chargeDataStructure[elementName] = elementText
//Add to field name to the list if not already added
(elementName in headers) ?: headers << elementName
}
chargeDataStructure
}
/**
* this is to create a csv row in string format
**/
def createRow = { recordDataStructure ->
def row = new StringBuffer()
headers.each {
if (row) {
row += delimiter + recordDataStructure[it] ?: ''
} else {
row += recordDataStructure[it] ?: ''
}
}
row.toString()+'\n'
}
//Build the whole data structure of Charge Records
chargeRecords.Charge.each { charge ->
chargeRecordsDataStructure << buildChargeDataStructure( charge )
}
//Build the rows
def rows = new StringBuffer()
rows << headers.join(',') +'\n'
chargeRecordsDataStructure.each { rows << createRow (it)}
//Write the rows into file
new File(outputFileName).text = rows
in soapui my project is :
Project
|__Datasource
|__request
|__groovy_code
|__DatasourceLoop
My Datasource contains 100 lines, each one is a request with different parameters.
My groovy_code save the id from the response of the request.
When i run my project, it executes 100 requests without errors.
groovy_code save only the first id.
What i want is to save id for each request, so 100 ids in different variables at project level
Here is my groovy_code:
import groovy.json.JsonSlurper
def response = context.expand( '${login#Response#declare namespace ns1=\'https://elsian/ns/20110518\'; //ns1:login_resp[1]/ns1:item[1]/ns1:response[1]}' )
def slurper = new JsonSlurper()
def result = slurper.parseText(response)
log.info result.data.id
testRunner.testCase.testSuite.project.setPropertyValue("token_id", result.data.id)
Thank you for your help
I never use SOAPUI PRO and I don't have access to datasource testStep or even datasource loop.
However based on the project structure you're showing I suppose that for each time datasource loop founds a element in datasource it sends the flow to request step so request and groovy steps are executed on each iteration; due to this I think that the problem is that your groovy code is overriding each time the same property with a new value.
Then to solve this you can try adding some variable suffix to your property name to avoid override each time the property value. For example you can add to token_id string a counter, some uuid, current ms etc.
For example you can use a counter as a suffix. To keep the counter value you've to save it in the context variable, this way this property are shared between your tests inside the current execution:
import groovy.json.JsonSlurper
// create a suffix function to generate
// the suffixs for your property names based on a count
def getSuffixNameProperty = {
// check if already exists
if(context['count']){
// if exists simply add 1
context['count']++
}else{
// if not exists initialize the counter
context['count'] = 1
}
return context['count']
}
def propertyName = "token_id" + getSuffixNameProperty();
def response = context.expand( '${login#Response#declare namespace ns1=\'https://elsian/ns/20110518\'; //ns1:login_resp[1]/ns1:item[1]/ns1:response[1]}' )
def slurper = new JsonSlurper()
def result = slurper.parseText(response)
testRunner.testCase.testSuite.project.setPropertyValue(propertyName, result.data.id)