I have a SoapUI Mock Service with multiple responses. I want to define a custom sequence for my responses and I do not necessarily use all of the responses in this particular test.
I have actually managed to get this to work in the past, but I think something changed in a newer version of the product and the feature stopped working. That was with a SOAP web service. Now I am mocking a RESTful web service and I have the same requirement to help me do my tests.
The SEQUENCE dispatch option is not what I want, because it will return all of the defined responses in the order in which they were created. The SCRIPT option is what I used previously but now all I can achieve with this is define one response to be generated. For this test I have no interest in examining some content of the request to decide which response to send back.
For example, if I have 8 responses defined, I just want to be able to specify that the following responses are returned:-
Response #2, then Response #3, then Response #4, then finally Response #7; so that Responses #1, #5, #6 and #8 are not used.
My question is posed in detail in the SmartBear forum here:-
simple scripting in a Mock Service - no longer works
I try as you post in the SOAPUI forum using consecutive returns statements with the response order an it doesn't work.
Instead of your groovy code as a DISPATCH script I purpose to use the follow groovy code as workaround, which consist in a use of a list to keep your responses in the desired order and keeping this list in the context an updating it each time using the following code:
// get the list from the context
def myRespList = context.myRespList
// if list is null or empty reinitalize it
if(!myRespList || !myRespList?.size){
// list in the desired output order using the response names that your
// create in your mockservice
myRespList = ["Response 2","Response 3","Response 4","Response 7"]
}
// take the first element from the list
def resp = myRespList.take(1)
// update the context with the list without this element
context.myRespList = myRespList.drop(1)
// return the response
log.info "-->"+resp
return resp
This code works as you expect, since context is keeping the list and each time this script returns the next response and when the list is empty it repopulate it an restart the loop again in the same order.
As an illustration when I use this mockService I get the follow script log:
EDIT
If as OP you've problems with your SOAPUI version because the returned string is between square brackets as ie: [Response 1], change the way that element is taken from the array using:
// take the first element from the list
def resp = myRespList.take(1)[0]
instead of:
// take the first element from the list
def resp = myRespList.take(1)
Note the [0].
With this change the return string will be Response 1 instead of [Response 1].
In this case the script will be:
// get the list from the context
def myRespList = context.myRespList
// if list is null or empty reinitalize it
if(!myRespList || !myRespList?.size){
// list in the desired output order using the response names that your
// create in your mockservice
myRespList = ["Response 2","Response 3","Response 4","Response 7"]
}
// take the first element from the list
def resp = myRespList.take(1)[0]
// update the context with the list without this element
context.myRespList = myRespList.drop(1)
// return the response
log.info "-->"+resp
return resp
Hope this helps,
Related
When running a speech to text api request from Google cloud services (over 60s audio so i need to use the long_running_recognize function, as well as retrieve the audio from a Cloud Storage Bucket), i properly get a text response, but i cannot iterate through the LongRunningResponse object that is returned, which renders the info inside semi useless.
When using just the "client.recognize()" function, i get a similar response to the long running response, except when i check for the results in the short form, i can iterate through the object just fine, contrary to the long response.
I run nearly identical parameters through each recognize function (a 1m40s long audio for long running, and a 30s for the short recognize, both from my cloud bucket).
short_response = client.recognize(config=config, audio=audio_uri)
subs_list = []
for result in short_response.results:
for alternative in result.alternatives:
for word in alternative.words:
if not word.start_time:
start = 0
else:
start = word.start_time.total_seconds()
end = word.end_time.total_seconds()
t = word.word
subs_list.append( ((float(start),float(end)), t) )
print(subs_list)
Above function works fine, the ".results" attribute correctly returns objects that i can further gain attributes from and iterate through. I use the for loops to create subtitles for a video.
I then try a similar thing on the long_running_recognize, and get this:
long_response = client.long_running_recognize(config=config, audio=audio_uri)
#1
print(long_response.results)
#2
print(long_response.result())
Output from #1 returns error:
AttributeError: 'Operation' object has no attribute 'results'. Did you mean: 'result'?
Output from #2 returns the info i need, but when checking "type(long_response.result())" i get:
<class 'google.cloud.speech_v1.types.cloud_speech.LongRunningRecognizeResponse'>
Which i suppose is not an iterable object, and i cannot figure out how to apply a similar process as i do to the recognize function to gain subtitles the way i need.
I have getuserdetails api where I need to send purchased item in array
API: api/getuserdetails/${id}
Method: post
body: {"uname":{
"purchaseitem": ["121","11","4","12345"]
}
}
In jmeter setup looks like
>>TP_1
>>CSVDataSet_ids
>>CSVDataSet_purchaseitem
>> ThreadGroup1
>>HTTP Req
>>JSR223 PreProcessor
>>View result tree
purchaseitem csv has values like
1231
12121
312232
13
1
42435
133
I want to pass "purchaseitem" array values fetched from CSV in comma separated manner as shown in body
I've tried something like this in JSR223 PreProcessor
def list = ${purchaseitem}
for (i=0;i<=list.size()-1;i=i+10)
{
def mylist = list.subList(i,i+10);
props.put ("mylist"+i,mylist)
}
Can someone please help? Or is there any function to solve this simple problem?
You're doing something weird
You won't be able to use CSV Data Set Config because it reads the next value with next virtual user/iteration
Your code doesn't make sense at all
If you need to send all the values from the CSV file at once you should be rather using JsonBuilder class, example code which generates JSON and prints it to jmeter.log file:
def payload = [:]
def purchasedtem = [:]
purchasedtem.put('purchaseitem', new File('/path/to/your/purchase.csv').readLines().collect())
payload.put('uname', purchasedtem)
log.info(new groovy.json.JsonBuilder(payload).toPrettyString())
More information:
Apache Groovy - Parsing and Producing JSON
Apache Groovy - Why and How You Should Use It
I have one test case which is called (started and finished) before every run of other test cases. It is something like 'test data preparation' test case. Output from this test case is list with some elements, list looks like this:
def list = ['Login', 'Get Messages', 'Logout', etc.]
List is different on every run. I need to transfer this list from 'test data preparation' test case to other test cases. Transfer will be between two Groovy scripts.
How to transfer list between two Groovy test steps in SoapUI?
As I understand it:
You have one TestCase, which you call from every other TestCase.
I assume this is done using a "Run TestCase" teststep?
You would like to be able to pass a list of strings
As I read it, parameters go one way. From the "external testcase" and back to the calling testcase. There is no "input" from each testcase to this "external testcase"?
The Groovy Script in your "external testcase" may then generate a String result, which in turn can be converted to something like an Array or ArrayList of Strings.
This could be a string with values separated by ;
def result = ""
result += "Entry1;"
result += "Entry2;"
result += "Entry3;"
// You may want to add a line of code that removes the last ;
return result
This result will then be easily retrieved from Groovy Scripts elsewhere, by adding a few lines of code.
If the Groovy Script is placed in another TestCase, but in the same TestSuite, you may retrieve the result using:
def input = testRunner.testCase.testSuite.getTestCaseByName("Name of TestCase").getTestStepByName("Groovy Script Name").getPropertyValue("result")
If it is placed in a TestCase in a different TestSuite, you may use:
def input = testRunner.testCase.testSuite.project.getTestSuiteByName("Test Suite Name").getTestCaseByName("Test Case Name").getTestStepByName("Groovy Script Name").getPropertyValue("result")
and then loop over the input doing something like:
for (def s : input.split(";")) {
log.info s
// Do your stuff here
}
I hope that makes sense...? :)
from groovy step 1 you shall return the list:
def list = ['Login', 'Get Messages', 'Logout']
return list
from groovy step 2 you can get this returned list
def result = context.expand( '${Groovy Script 1#result}' )
list = result.tokenize('[,] ')
list.each{
log.info it
}
note that you get a string that you have to convert back to a list (tokenize).
I did this with SOAPUI pro.
Another way (ugly) would be to store the list in a custom property in groovy script 1 (using testRunner.testCase.setPropertyValue("myList",list.toString())
and to recover it in groovy step 2 (testRunner.testCase.getPropertyValue("myList")
I hope that will help
EDIT : if list elements contain spaces
this is not very clean and I hope someone will help to provide something better but you can do the following :
list = "['Login - v1', 'Get Messages - v2', 'Logout - v1']"
list = list.replace('\'','\"')
def jsonSlurper = new groovy.json.JsonSlurper()
list = jsonSlurper.parseText(list)
list.each{
log.info it
}
Alex
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've this code by which I am trying to set the value of a Key (a json node id). But its not setting the value. Log.info statement is showing right values.
Key= context.expand( '${#Project#key}' )
Value= context.expand( '${#Project#value}' )
Binding binding = new Binding()
binding.setVariable("v", "$Value")
binding.setVariable("k", "$Key")
log.info(binding.getVariable("v")) // gives me the value 1234
log.info(binding.getVariable("k")) // gives me the value request.id
def SetKey = new GroovyShell(binding).evaluate( "k=v")
Can someone please comment on whats wrong in this code. and how can I correct it.
Edit: Explanation of the issue
In SoapUI I've some json nodes saved in data source like this request.id and request.app.id and there expected values in Value column which I am fetching through Key and Value above. I am hoping to change the value of a json node to its respective value at run time. So for each iteration of data source, it should set the correct value of that particular json node. Befor the above code I've parsed my json request by json slurper and after the above code I am building the json again by Json builder and running the request. Parsing and running the request works fine, its just that I couldnt set the value of the json node.
If your keys are just dotted names, you could simply use some string manipulation, no need to involve the Groovy parser.
For example, if they all begin with request:
def steps = Key.split(/\./)
if (steps.size() < 2 || steps[0] != 'request') {
throw ...
}
def obj = request
if (steps.size() > 2) {
steps[1..-2].each {
obj = obj[it]
}
}
obj[steps[-1]] = Value