03 December 2007 - 2.0-beta2 |
The Groovy Script step allows you to specify an arbitrary Groovy script during the execution of a TestCase. The script has full access to the soapUI object model and can thus perform a variety of tasks, for example:
If you need to add external libraries to the soapUI classpath for your groovy scripts (for example jdbc drivers), put these in the bin\ext folder under the soapUI installation, these will be read upon started and added to the soapUI classloader. (not currently possible in the Java WebStart version of soapUI).
The Groovy Script editor is a straight forward text-editor without not to many bells-and-whistles except undo/redo functionality;
The editor has three components (from top to bottom):
log
objectThe editor popup shown in the screenshot above has standard editing/navigation actions
When a groovy script is executed, the following context variables are set for the script to use:
testRunner
: the TestRunner
running the current TestCase, this will for now always be an instance of
WsdlTestCaseRunnercontext
: the TestRunContext
running the current TestCase, this will for now always be an instance of
WsdlTestRunContextlog
: a standard log4j Logger
object available for logging arbitrary informationWhen the script is run from inside the editor using the toolbars "Run" button, the first 2 objects will be set to
mock implementations allowing limited access to their actual functionality. The log
object will in
this case write to the log window in the editor, when running from inside a TestCase the log will write to a
"groovy log" tab in the main soapUI log.
If you want to fail the script due to some internal error throw an Exception from the script containing the error message (see example below)
The following properties are available from within a groovy-script:
Getting started with Groovy is not as easy as it may seem... here are some examples to get you started:
// get request property def request = testRunner.testCase.getTestStepByName( "Request 1" ); def property = request.getProperty( "request" ); // parse out textnodes to modify def node = new groovy.util.XmlParser(false,false).parseText(property.value); def textNodes = node["soapenv:Body"]["sam:getContactInfo"]["String_1"][0].children() // modify textNodes.clear(); textNodes.add( "test" + System.currentTimeMillis() ); // write back to string def writer = new java.io.StringWriter(); def printer = new groovy.util.XmlNodePrinter( new PrintWriter( writer )); printer.print( node ); // set property property.setValue( writer.toString() )
// check if time is set startTime = context.getProperty( "startTime" ) if( startTime == null ) { startTime = System.currentTimeMillis() context.setProperty( "startTime", startTime ) } timePassed = System.currentTimeMillis() - startTime if( timePassed < 60000 ) { // countdown and set name context.currentStep.name = "Groovy Step - " + (60000-timePassed) + "ms left" log.info "timePassed = " + timePassed Thread.sleep( 1000 ) testRunner.gotoStep( 0 ) } else { // reset name and pass on context.currentStep.name = "Groovy Step" log.info "timePassed = " + timePassed + ", exiting.." }
// read the file def properties = new java.util.Properties(); properties.load( new java.io.FileInputStream( "testprops.txt" )); def targetStep = testRunner.testCase.getTestStepByName( "Properties" ); // assign single property targetStep.setPropertyValue( "myproperty", properties.getProperty( "myproperty" )); // assign all properties def names = properties.propertyNames(); while( names.hasMoreElements() ) { def name = names.nextElement(); targetStep.setPropertyValue( name, properties.getProperty( name )); }
// add a properties step testRunner.testCase.addTestStep( "properties", "another step" );
// fail randomly if( Math.random() > 0.5 ) throw new Exception( "A random error has occurred!" );
If you select the "Maintain HTTP Session" option in the TestCase Options Dialog, an internal HttpState
object
will be maintained for the entire TestCase, which includes any cookies set by the target server. The following script reads all
cookies currently set in the HttpState and writes them to the groovy log:
def state = context.getProperty( com.eviware.soapui.model.testsuite.TestRunContext.HTTP_STATE_PROPERTY ) assert state != null : "Missing HttpState.." def cookies = state.cookies assert cookies.length > 0 : "Missing cookies.." for( c in 0..cookies.length-1 ) log.info cookies[c].name + " = " + cookies[c].value
If you on the other hand want to set some cookie before making a request, do as follows:
def state = context.getProperty( com.eviware.soapui.model.testsuite.TestRunContext.HTTP_STATE_PROPERTY ) assert state != null : "Missing HttpState.." state.addCookie( new org.apache.commons.httpclient.Cookie( "http://www.mydomain.com", "SessionID", "1234" ))
The GroovyUtils class simplifies several common scripting tasks. Instantiate GroovyUtils from within any Groovy Script in soapUI (MockResponse, Script Assertion, etc) using:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
GroovyUtils currently includes the following (few) methods:
projectPath
: a property holding the path to the containing project, useful for accessing
data files in same foldersetPropertyValue( String testStepName, String propertyName, String value )
: sets the specified
property valueexpand( string )
- expands the specified Property Expansion stringgetXmlHolder( String xmlPropertyOrString )
: Creates an XmlHolder
object (see below) for
easily accessing/modifying contents of an XML document using XPath expressions. The argument must either be
a TestStep property in the TestStepName#PropertyName
format or a valid XML stringThe above mentioned XmlHolder object has the following methods:
getNodeValue( String xpath )
: returns the value of the first node pointed to by the specified
XPath expression (can be replaced by holder[xpath] expression, see below )getNodeValues( String xpath )
: returns a String array containing the values of all nodes
pointed to by the specified XPath expression.getDomNode( String xpath )
: returns the DOM Node of the first node pointed to by the specified
XPath expression.getDomNodes( String xpath )
: returns a DOM Node array containing all nodes
pointed to by the specified XPath expression.setNodeValue( String xpath, String value )
: sets the content of the first node pointed to by
the specified XPath expression to the specified value (can be replaced by holder[xpath] = value expression, see below )declareNamespace( String prefix, String namespaceURI )
: declares a namespace that will be used in
a following get/set operation, can also be set with holder.namespaces[prefix] = namespaceUri (see example below)getNamespaces()
- returns a Map of prefixes to namespace URI:s that will
be used in XPath expressionsremoveDomNodes( xpath )
- removes all DOM nodes matching the specified
XPath expressionxml
: property containing the updated xml stringxmlObject
: property containing the parsed XMLBeans XmlObject for the xml stringprettyXml
: property containing the pretty-printed updated xml stringupdateProperty()
: if the XmlHolder was created from a TestStep property, that property will be updated
with the currently held xml (see example below)updateProperty( boolean prettyPrint )
: same as previous, with option to pretty print the updated xml.
Defaults to false when not specified.If any of the specified XPath expressions contains no namespace declarations or none have been declared
using the declareNamespace
method, those present in the XML Message
will be used in the same way as in Property Expansion.
Some examples of both the GroovyUtils and XmlHolder:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context ) log.info( groovyUtils.projectPath ) // create holder for last response and log requestId def holder = groovyUtils.getXmlHolder( "Book Author Search#Response" ) log.info( holder.getNodeValue( "//ns1:RequestId" )) // create holder for request and set id holder = groovyUtils.getXmlHolder( "Book Author Search#Request" ) holder.setNodeValue( "//ns:SubscriptionId", ""+Math.random() ) // update request with updated xml holder.updateProperty()
Also, XmlHolder implements the Map interface for shorter syntax when setting and getting node values, the corresponding above calls can be replaced by:
... log.info( holder["//ns1:RequestId"] ) ... holder["//ns:SubscriptionId"] = ""+Math.random() ...
If the specified XPath expression returns multiple values when getting a value, a String array is returned instead:
for( author in holder["//ns1:Author"] ) log.info( author )
If you are not sure of the namespace-prefix to use, you can declare it yourself:
def holder = groovyUtils.getXmlHolder( "Book Author Search#Response" ) holder.namespaces["abc"] = "http://webservices.amazon.com/AWSECommerceService/2006-11-14" log.info( holder["//abc:RequestId"] )