I want to do the following in soapUI using Groovy:
Select random value and correspondating data from database
Get the response from webservice
Compare my database data with the response from the webservice
To achieve this I have the following steps definied:
Created property object for the test suite
Groovy Script to get the random and correspondating values from database
Transformation to put the random value into the request
Webservice call to get response
Groovy Script to compare the values from my database with the response of the webservice
I did the same steps for other tests already by putting the values from database into the property object in step 2 and reading them from there in step 5. But up to now the values were always normal String or int. In the response I get in my current test case I get a list back. So I create an array and filled it with bean objects my wanted data in step 2. In step 5 I parse my XML-String and convert the data into an Object-Array too. So I can compare all attributes of them.
I wrote the whole test case in a singular script and tested it on groovy console first. When I started to transform it to soapUI and working with the property to "transport" the data from step 2 to step 5 my problem occurs as it looks like I can't put an Arraylist to the properties (see error message below).
Now I'm confused that this is not possible as I can easily put SQL-Instances in the properties:
def contextSqlInstanz = Sql.newInstance(urlH2, userH2, passwordH2, driverH2)
context.setProperty( "contextSqlInstanz", contextSqlInstanz )
sql = context.getProperty("contextSqlInstanz");
So how I can transport my Array, filled the Objects, from step 2 to step 5 to compare it with my webservice response. I DON'T want to convert both to strings and compare if the strings are equal but I want to compare each attributes of my bean-class by hand.
Bean Class:
class myBean {
String value1;
String value2;
...
}
Reading my local database, generating the beans and put them into a list
function getdata() {
def liste = []
// sql-statements
sql.eachRow(...) {
def myBean = new myBean();
myBean.value1 = it.value1.toString();
myBean.value2 = it.value2.toString();
...
liste.add(Schluesselwert)
}
return liste
}
Trying to put the list into properties
sollListeH2 = getdata()
def props = testRunner.testCase.getTestStepByName("P_testcase")
props.setPropertyValue( "sollListe", sollListeH2)
results in:
groovy.lang.MissingMethodException: No signature of method: com.eviware.soapui.impl.wsdl.teststeps.WsdlPropertiesTestStep.setPropertyValue() is applicable for argument types: (java.lang.String, java.util.ArrayList) values: [sollListe, [value1#15d4334, value2#1e739c8, ...]] Possible solutions: setPropertyValue(java.lang.String, java.lang.String), getPropertyValue(java.lang.String) error at line: 91
As I didn't find another way I did it the ugly way by putting each value as an own property into the propteries
Setting the props in step 2:
def convertVectorToProps(vector) {
def size = vector.size();
def props = testRunner.testCase.getTestStepByName("P_testcase")
props.setPropertyValue("sollSize", size.toString())
for(int i=0; i < size; i++) {
props.setPropertyValue("myBean.value1" + i, vector.value1[i]);
props.setPropertyValue("myBean.value2" + i, vector.value2[i]);
...
}
}
Reading the props in step 5 and build new vector:
def convertPropsToVector() {
def props = testRunner.testCase.getTestStepByName("P_testcase")
def sollSize = props.getPropertyValue("sollSize").toInteger()
SollListe = [];
for(int i=0; i < sollSize; i++) {
def myBean = new myBean();
myBean.value1 = props.getPropertyValue("myBean.value1" + i);
myBean.value2 = props.getPropertyValue("myBean.value2" + i);
SollListe << myBean
}
return SollListe
}
Related
Beginner alert! I have a simple Groovy script that aims to break an argument list into key-value pairs, stored in an associative array (HashMap?). The code works fine until the point where it splits the parameters, but when it tries to put the results back into the array, it throws an exception, stating it cannot access a null element.
I suppose the reason for this is that it can't access the variable that was declared outside the loop.
Here's the script:
def input = "https://weyland-yutani.corp/engineering/bio?param1=1¶m2=2"
def params = [:] // wanna store key-value pairs here
if (input.split('\\?').size() >= 2) {
def p = input.split('\\?').last() // get the param string
p.split('\\&').each { // cut the string into an argument list
def keyval = it.split('=') // cut the argument into a key-value pair
println keyval // <-- prints "[param1, 1]", looks okay
params[keyval[0]].put(keyval[1]) // ERROR: "Cannot invoke method put() on null object"
//params[keyval[0]].add(keyval[1]) // ERROR, same sh**
}
}
Error message:
Caught: java.lang.NullPointerException: Cannot invoke method put() on null object
java.lang.NullPointerException: Cannot invoke method put() on null object
at jdoodle$_run_closure1.doCall(jdoodle.groovy:10)
[...]
As it was stated in this article, the way you declare a variable can affect it's scope, but none of my tries succeeded.
Could you give me an advice what am I missing?
The following code:
def input = "https://weyland-yutani.corp/engineering/bio?param1=1¶m2=2"
def params = input.tokenize('?').last().tokenize('&').collectEntries { keyval ->
keyval.tokenize('=')
}
println params.getClass()
println params
demonstrates one way of doing this. When run, this prints:
─➤ groovy solution.groovy
class java.util.LinkedHashMap
[param1:1, param2:2]
─➤
As an alternative, if you are ok with using an external library, you could use a url parsing class. This example from HttpBuilder (which is a tad outdated at this point, there are probably others out there):
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2')
import groovyx.net.http.URIBuilder
def input = "https://weyland-yutani.corp/engineering/bio?param1=1¶m2=2"
def uri = new URIBuilder(input)
println uri.query.getClass()
println uri.query
which, when run, prints:
─➤ groovy solution2.groovy
class java.util.HashMap
[param1:1, param2:2]
─➤
As another example, this time using google http client library class GenericUrl:
#Grab('com.google.http-client:google-http-client:1.39.1')
import com.google.api.client.http.GenericUrl
def input = "https://weyland-yutani.corp/engineering/bio?param1=1¶m2=2"
def url = new GenericUrl(input)
println (url instanceof Map)
url.each { k, v ->
println "$k -> $v"
}
println "value of param1: ${url.param1}"
which, when executed prints:
─➤ groovy solution3.groovy
true
param1 -> [1]
param2 -> [2]
value of param1: [1]
─➤
It should be noted that google does the right thing here. When asking for the value of a parameter, the answer should really be a list. This is because you can say ?a=1&a=2&a=3 which from what I understand should be interpreted not as replacing the value of a, but rather as a being a list of values 1, 2, 3.
So when you ask the google library for the value of a param, you get back a list which in this case happens to be one param long.
There is no code that is ever putting anything in params so when you do params[keyval[0]] that will always evaluate to null, so params[keyval[0]].put(keyval[1]) can't work because you are invoking .put on a null reference.
I have written a custom JSR223 PostProcessor in order deduplicate a JSON Extractor array, and then build all of the needed variables for a ForEach Controller
import java.util.stream.Collectors;
def previousValuesMatchNrAsString = vars.get("distinctServiceIds_matchNr");
def previousValuesMatchNr = previousValuesMatchNrAsString ? previousValuesMatchNrAsString.toInteger() : 0;
for(i = 1; i <= previousValuesMatchNr; i++) {
vars.remove("distinctServiceIds_" + i);
}
vars.remove("distinctServiceIds_ALL");
vars.remove("distinctServiceIds_matchNr");
def values = vars.get("serviceIds_ALL").split(",");
def newValues = Arrays.stream(values).distinct().collect(Collectors.toList());
def newValuesCount = newValues.size();
def joinesNewValues = String.join(",", newValues);
vars.put("distinctServiceIds_ALL", joinesNewValues);
newValues.eachWithIndex { var, idx -> vars.put("distinctServiceIds_" + (idx + 1), var) };
vars.put("distinctServiceIds_matchNr", newValuesCount.toString());
I have to cleanup variables first, because this JSR223 PostProcessor runs into another ForEach Controller, and then I have to populate distinctServiceIds_ALL, distinctServiceIds_matchNr and all of the indexed variables in order to use distinctServiceIds as "Input variable prefix" for my ForEach Controller.
Although this works, it seems very hacky to me and I wonder if there's some Groovy function, or something else, to do all of that work.
there are many additional methods defined in groovy
as soon as vars contains type of JMeterVariables to remove old vars you could collect required entries from iterator and call remove for each one
the extension groovy methods for iterator could be found in groovy docs
vars.getIterator().findAll{ it.getKey().startsWith('distinctServiceIds_') }.each{
vars.remove(it.getKey())
}
because of groovy it could be simplified to this:
vars.iterator.findAll{ it.key.startsWith('distinctServiceIds_') }.each{
vars.remove(it.key)
}
the same with other generic types: List, Maps, etc
collecting unique values and transforming to map:
def values = [111,222,333,444,444,444,444]
def valMap = values.unique().indexed().collectEntries{k,v-> ['distinctServiceIds_'+(k+1),v] }
vars.putAll(valMap)
so, check groovy jdk extension documentation
I have a context property named 'flights'. I want to check if there is no value for this property, then go to the 'Iteration' test step, else set the first value of the property as a test case property.
Now what I want to do is perform a compare using this test case property value with a couple of arrays. Below is the scenario;
Check if value is in the villas array, if so +1 to VillasCount, else check in hotels array, if in there then +1 to beachCount else +1 to noCount.
Code is below:
// define properties required for the script to run.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def dataFolder = groovyUtils.projectPath
//Define an empty array list to load data from datasheet
def dataTable_properties = [];
int villasCount = context.getProperty("villasCount")
def lines = new File(dataFolder + "/Test.csv").readLines()
def villas = []
lines.eachWithIndex { line, index ->
if (index) {
def data = line.split(',')*.trim()
if (data[0]) villas << data[0]
}
}
log.info "Villas : ${villas}"
context.setProperty("villasCount", villasCount)
Maybe something like:
for(f in flights){
if(villas.contains(f)){
villasCount = villasCount + 1
}
}
Not 100% sure what you needed to compare, but you could easily expand this to check whatever you wanted.
If this is way off please provide more information on what you were trying to compare.
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
I have two lists
def flagList = SystemFlag.list()
this contains the domain objects of one table
I have another list which I create using a query. One of the parameter in the object of this list is contained in the flagList. How can I find if an id of FlagList is present in the second list?
I can do it in plain java but I need to use Groovy for this.
If I understood you correctly you have this situation:
def listeOne = [1,2,3,4,5]
def listTwo = [2,5,1]
You want to see if '2' of 'listTwo' is in 'listOne'.
Find a specific value:
def found = 2 in listTwo //returns a boolean of the interger 2 is in listTwo
Search for common value of both lists:
def intersectionsList = listOne.intersect(listTwo) //gives you a list of value that are in BORTH list
You can also iterate like this:
listTwo.each { value ->
if(value in listOne) println value //or do something lese
}
Alternatively:
listTwo.each { value ->
listOne.find {value}?.toString() //you can perform an action on the object found in listOne. using '?.' will make sure no nullpointer will be thrown if there is no result.
}
I found it using
def it = itemtofindsomehow
list.findIndexof { iterator ->
iterator.domain.id == it.id
}