I am a beginner in soapui testing. Hopefully you can help me solving this problem.
In my test project I have a test suites which contains several test cases. Multiple test case will start the same test case. To run this test case I need some property values to be transferred to this test case.
I tried to achieve this in two ways. But I failed in both.
I tried to call the test case and set the needed properties in the test case. I start the test case from a Groovy script. But I couldn't find a good example how to set the properties in the called test case.
I tried to get the property values of the calling parent test case inside the called test case. It looks like the parent test case that called the test case isn't available in the context of the running test case.
The test cases, that will call the same test case, will be run in parallel. So, I think it isn't a solution to first set the property values and then start the test case, because they will be overwritten by the other test cases that run at the same time. Also using test suite properties for these values won’t work because of running the test cases in parallel.
My test project looks like this.
MyProject
TestSuite_APLtests
TestCase_user_01
Properties test step
Run_test <groovy script>
Step_01
…..
TestCase_user_02
Properties test step
Run_test <groovy script>
Step_01
…..
TestCase_General
Properties test step
POST sessions
Step_01
…..
The ‘Properties test step’ of each ‘TestCase_user_’ contains a user and password needed in test case ‘TestCase_General’ and will be different for each test case.
In the ‘Run_test’ groovy script of each ‘TestCase_user_’ the test case ‘TestCase_General’ is started by using:
def myTestSuite = testRunner.testCase.testSuite.project.getTestSuiteByName("TestSuite_APLtests")
def myTestCase = myTestSuite.getTestCaseByName("TestCase_General")
myTestCase.run(null, false)
How can I add the properties user and password to the run comment that starts the test case?
If I try to get the property values with a groovy script in test case ‘TestCase_General’ I don’t know how to determine which test case has called ‘TestCase_General’. I found some posts on internet that suggests to use: context.getProperty("#CallingRunTestCaseStep#") to determine the calling test case. But this value is null. And when I try to check if the calling test case is available in the context by using: context.hasProperty("#CallingRunTestCaseStep#") this is false, so this doesn't work to find the calling test case.
Can someone tell me what the solution will be to get this working.
Thanks,
You can set Test Case properties from groovy script with setPropertyValue(name,value) method, however if you run the Test Cases in parallel, this properties as you said will be overwritten for each Test Case calling TestCase_General. So instead of use setPropertyValue you can pass the context properties through the run(StringToObjectMap properties, boolean async) method in the WsdlTestCase.java class. Your groovy code to call TestCase_General could be:
import com.eviware.soapui.support.types.StringToObjectMap
// get test suite
def myTestSuite = testRunner.testCase.testSuite.project.getTestSuiteByName("TestSuite_APLtests")
// get your test case
def myTestCase = myTestSuite.getTestCaseByName("TestCase_General")
// set the user and password properties in the context
context.setProperty("user","userTestCaseN")
context.setProperty("password","passwordTestCaseN")
// run the testCase passing the context
def contextMap = new StringToObjectMap( context )
myTestCase.run(contextMap,false);
To access the context properties in the groovy script of your TestCase_General use this code:
context.getProperty("userPassword")
Or if you prefer to use context.expand:
context.expand('${#user}')
Note that the use of # depends on how you are accessing the properties.
If you also need to use the context properties in the SOAP Test Request of your TestCase_General use this way ${#propetryName} i.e:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Header/>
<Body>
<request>
<user>${#user}</user>
</request>
</Body>
</Envelope>
Hope this helps,
Related
Is it possible to / how do you run a groovy script from a SoapUI assertion without copy/pasting the script into all of your test steps where you need the same script executed? Is it possible to write a script outside of the assertion and run the script like you are calling a method? So that you can reuse the assertion script in multiple test steps.
So far, I've tried to call a groovy test step from within the assertion, but the run() method requires a testRunner variable which is unavailable from within the assertion. I've also tried to write a groovy script as a subsequent test step (not an assertion) that calls another groovy test step script, but I was unable to transfer the response from one test step to the next (Honestly, I'd rather not create test steps that are really just assertions).
Note: this is not a duplicate of How to create variables in soapui test case that can be accessed across all test steps - groovy test step & script assertion test step? because that question pertains to storing properties, not reusing scripts.
I was able to finally figure out my 2nd approach: add another groovy script as a subsequent test step that has assertions and passes the response. The script is:
context.response = context.expand('${MyTestStep#Response}') // store response to context variable
Object result = testRunner.testCase.testSuite.testCases['Validate Response'].testSteps['Validate Response'].run(testRunner, context)
if(result.getError() != null) {
log.error("error", result.getError())
assert false
}
assert true
MyTestStep is the test step before the groovy script. Validate Response is the name of the test case of the groovy script which is also called Validate Response and is executed via the run method.
Goal
I want "regular" test steps to break the SoapUI test case while a distinct subset of test steps should be allowed to fail.
Rationale
I have a SoapUI test case that performs a rather complicated functional test where some optional details are checked by additional JDBC test steps. Since these details are "optional", the test case should not fail (i.e. it should turn green) even if one or more of these JDBC tests fails.
Almost there
If the requirement would allow all test steps within the test case to fail, I could simply toggle the test case behaviour:
Open the TestCase Options dialog (from the TestCase toolbar) and uncheck the Abort on Error option. When you run the TestCase that step still fails but SoapUI will continue running through the other TestSteps
Functional Tests | Data-Driven Tests (SoapUI.org)
Question
Can this goal be achieved by a setting or property on test step level (especially: without Pro version)?
Is there a Groovy solution similar to setFailOnError/setFailTestCaseOnErrors methods on WsdlTestCase but on test step level?
I have solved it by inserting two Groovy test steps that
store the current test case settings on (temporary) test case custom property fields;
turn of the error behavior before the optional steps;
restore the previous error behavior after the optional steps from the (temporary) properties.
Before: disableFailOnErrorBehavior.groovy:
testRunner.testCase.with {
// Store current TestCase options in (temporary) TestCase properties.
setPropertyValue('_failOnError', failOnError.toString())
setPropertyValue('_failTestCaseOnErrors', failTestCaseOnErrors.toString())
log.debug "Saved FailOnError behavior: ${failOnError}, ${failTestCaseOnErrors}."
// Allow following TestSteps to fail without aborting the TestCase immediately.
setFailOnError(false)
setFailTestCaseOnErrors(true)
log.info "Set FailOnError behavior: ${failOnError}, ${failTestCaseOnErrors}."
}
After: restoreFailOnErrorBehavior.groovy:
testRunner.testCase.with{
// Use (temporary) TestCase properties to restore initial TestCase options.
setFailOnError(getPropertyValue('_failOnError').toBoolean())
setFailTestCaseOnErrors(getPropertyValue('_failTestCaseOnErrors').toBoolean())
log.info "Restored FailOnError behavior: ${failOnError}, ${failTestCaseOnErrors}."
// Remove (temporary) TestCase properties.
removeProperty('_failOnError')
removeProperty('_failTestCaseOnErrors')
log.debug "Clean up temporary properties: done."
}
These scripts rely on two methods to change the test case behavior:
WsdlTestCase.getFailOnError()
WsdlTestCase.getFailTestCaseOnErrors()
Right Click on Test Case;
Select Options; Under Basic Tab --
Deselect Abort on Error [If it is checked]
I developed some SoapUI cases which set a property at the start of each test case by reading the properties from a file. This works fine, I can then access each property (lets say propertyA) by the syntax ${propertyA} in each test request step.
Now I realized that one of the properties is the same for each test case, so I thought I create a testsuite property for that purpose and remove the property definition from the test case property files. First my test cases all failed, cause now 'propertyA' was not known any more, but I figured out that (according to http://www.soapui.org/Scripting-Properties/property-expansion.html) one solution is to replace each reference to propertyA by #testSuite#propertyA.
This is kind of tedious, though, so I thought of creating a groovy script at the beginning of each test case which creates a test case property from the test suite property. According to
http://www.soapui.org/Scripting-Properties/tips-a-tricks.html I thought that a script like
def testSuiteProperty = testRunner.testCase.testSuite.getPropertyValue("propertyA")
testRunner.testCase.setPropertyValue("propertyA", testSuiteProperty)
should do the job. And if I log.info the value of testSuiteProperty this gives indeed the desired value, and also if I assign the testCase property to some variable and log.info it, it shows the correct value.
However, in the next test step, propertyA is not known. Just to make sure I tried to use ${#testCase#propertyA} there, but that is also not known. What did I get wrong here?
I think your problem is that the t of testCase in ${#testCase#propertyA} must be uppercase: ${#TestCase#propertyA}. If I add a groovy test step with your code:
def testSuiteProperty = testRunner.testCase.testSuite.getPropertyValue("propertyA")
testRunner.testCase.setPropertyValue("propertyA", testSuiteProperty)
And then I add a SOAP test step with follow xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:open="http://www.openuri.org/">
<soapenv:Header/>
<soapenv:Body>
<open:procesa>
<open:selector>${#TestCase#propertyA}</open:selector>
</open:procesa>
</soapenv:Body>
</soapenv:Envelope>
It works correctly, however if I use ${#testCase#propertyA} the property value is not found.
Besides you can check if correct value is used in the raw tab in the left side of the SOAP test step request. In this tab the request is show with the properties replaced by it's values.
Hope this helps,
I'm running into copy-pasting a lot of code at the moment in my SoapUI projects, and thought I'd have some sort of library of helper functions that can carry out most of my tasks.
So I have a test suite for this, and the code itself is in a Groovy Script test step in this test suite. The idea is that I make my helper methods available to the context I'm in (a REST test request step).
It instantiates fine and all that, but the problem is that when I want to invoke run(testRunner, context), I am not having access to the testRunner property. I've read something about that this is how it is.
Anyone know a way around this?
I am using the same method as you for script library. I used the method described by Kerry Doan at http://www.doan.me/script-library-in-soapui-free.aspx
When i tried to access this script library from project load script i did not have access to the testRunner so i created the testRunner object and as i did not have access to the context object i had to create that too.
Check out the code below.
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner
import com.eviware.soapui.support.types.StringToObjectMap
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext
//to create the testRunner object I need a testCase object and a new StringToObjectMap
//I initially used the test case in the script library but as i needed the
//testRunner object to the test case being executed so i created the object to
//the test case being executed.
//I did not want to worry about test suite or test case names so i used their index
//assuming that there will be at least one test suite and at least one test case when
//this script is run
testCase = project.getTestSuiteAt(0).getTestCaseAt(0)
tcRunner = new WsdlTestCaseRunner( testCase, new StringToObjectMap() );
//A context is essentially a WsdlTestRunContext object and as you can see below all i
//have done to create that is pass it a test step object which was obtained by using index
//rather than name.
tStep = testCase.getTestStepAt(0)
tcContext = new WsdlTestRunContext(tStep)
//my script library is in a seperate project called `Script Library` and all the
//groovy scripts are in a test suite called `Script Library`
scripts = project.workspace.projects["Script Library"].testSuites["Script Library"];
scripts.testCases["Scripts"].testSteps["runTest"].run(tcRunner, tcContext);
I'm trying to modularize my test cases, so I'm running a shared test case (as a procedure) that does something useful and returns a result value. As I need to pass-in non-string input properties, I have to run the test case from groovy:
def findLoopEndTC = testRunner.testCase.testSuite.testCases["TestCase - Find Loop End"]
assert findLoopEndTC != null, "Referred TC not found"
def runContext = new com.eviware.soapui.support.types.StringToObjectMap()
runContext.put("TestStepContext", context)
def runner = findLoopEndTC.run( runContext, false )
assert runner.status != com.eviware.soapui.model.testsuite.TestRunner.Status.FAILED : runner.reason
I've learned that the test case is run using the SINGLETON_AND_WAIT mode which ensures that the TestCase itself is run in a thread-safe way.
My question is how to return a value from the run test case in a thread-safe way?
I tried runner.getRunContext().getProperty("Result"), but it seems that the context properties are no longer there. So there seems to be only the "classical" way, findLoopEndTC.getPropertyValue("Result"), but this is aparently not thread-safe.
Are there other possibilities?
I use the free version of SoapUI.
I had the same problem. If I understand you correctly, this is what you want:
You’ve put the ‘calling’ context into a new context ‘runContext’:
context.get("TestStepContext").put("Results",resultList)
which has been passed in as the context for the test case to be run (synchronously). I’ll call the test case to be run ‘B’:
def runner = findLoopEndTC.run( runContext, false ) //in calling test case
To get something useful back from ‘B’, somewhere in it you need to put a value back into TestStepContext, e.g.:
context.get("TestStepContext").put("Results",resultList) //My results happened to be a list
In the calling test case, the line you need after the call to run the test case is:
def testResults = runContext.get("TestStepContext").get("Results")
Hope this makes sense.
I've been trying to work this out for the last few days too. I haven't been able to work out how to make it thread safe but I have an alternative approach which I think works pretty well.
I've based it on this http://forum.soapui.org/viewtopic.php?f=2&t=4681#p15731 suggestion from the SoapUI team. I found with the above solution it was still not thread safe, 99% of the time this worked but I found sometimes it's possible you can have two test cases both breaking out the loop at the same time.
To deal with this I set runningDeleteCar to the the hashcode for the current testRunner when it's broken out of the loop. I then double check this to make sure that some other test case hasn't gone in and changed it, if it doesn't match I just go back to the while loop. This stops the situation of two test cases breaking out at the same time.
This approach basically means only one test case can go through the shared test case at a time.