26 September 2007 - 1.7.6 | home user-guide eclipse jbossws intellij netbeans maven 1.X/2.X PDF files forums bugs sourceforge

Home
Getting Started
User Guide

- Overview
  - Tabbed Desktop
  - License Management
  - Preferences
  - XPath Selection
  - Script Library
- Workspaces
- Projects
- Interfaces
  - Interface Viewer
- Operations
- Working with Requests
  - Form Editor
  - Overview View
  - Outline Editor
  - Message Inspectors
  - Attachments/Inline Files
- Functional Testing
  - Getting Started
  - TestSuites
  - TestCases
    - Test Requests
      - Assertions
      - Editor Wizards
    - Property Transfers
    - Conditional Gotos
    - Groovy Scripts
      - Examples
      - GroovyUtils
    - Properties Step
    - Delay Step
    - Mock Response
    - DataSource
    - DataSource Loop
  - Property Expansion
- Load Testing
  - Getting Started
  - Limit & Strategies
  - Execution
  - Assertions
  - Diagrams
  - JMeter comparison
- Mocking
  - Getting Started
  - Mock Services
  - Mock Operations
  - Mock Responses
- Usage Scenarios
  - Data-Driven Testing
  - Template-Driven Testing
  - Interactive Testing
  - Surveillance Testing
- Tool Integrations
  - Code Generation
  - WSDL Generation
  - WS-I Tools
  - Apache Tcp-Mon
- CommandLine Tools
  - TestCaseRunner
  - LoadTestRunner
  - MockServiceRunner
  - ToolRunner
- Keyboard shortcuts

IDE/Tool Plugins
Search soapUI site
Project Documentation

- About soapUI
- Project Info
- Project Reports

## Groovy Scripts

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:

- Read data from an external data source and write it to another steps properties
- Control TestCase flow based on outcome of some previous step or external invocation
- Trigger the execution of other TestSteps and/or TestCases
- Perform advanced response validations not possible with existing assertions
- Write the results of some previous TestStep to an external source (reporting, etc...)
- etc..

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

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):

- A toolbar : currently only containing a "Run" button
- A script editor : standard text-editor
- A log inspector : can be written to using the script contexts `log` object
- A statusbar : displays caret position and a progressbar during script execution

The editor popup shown in the screenshot above has standard editing/navigation actions

### Script Execution

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 WsdlTestCaseRunner
- `context` : the TestRunContext running the current TestCase, this will for now always be an instance of WsdlTestRunContext
- `log` : a standard log4j `Logger` object available for logging arbitrary information

When 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)

### Context Properties

The following properties are available from within a groovy-script:

- ThreadIndex - the index of the created thread when running under a LoadTest. This value will never change for a given TestCase during its run time. New threads will simply get an incremented index, the mod of this value could for example be used as an index into a data-file (to handle changes in number of threads). When not running under a LoadTest the value of this property will be "0".
- RunCount - tells how many times the TestCase has been run by its thread (not in total) when running under a LoadTest. When not running under a LoadTest the value of this property will be "0".
- LoadTestRunner - the current LoadTestRunner when running under a LoadTest, null otherwise.
- #HTTP_STATE - the HttpState maintained by the TestCase if it has been set to do so in the TestCase Options dialog.

### Groovy Script Examples

Getting started with Groovy is not as easy as it may seem... here are some examples to get you started:

#### Modification of a Request xml:

    // 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() )

#### Restarting a test after a certain time

    // 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.."
    }

#### Reading properties from a file and assigning them to a Properties Step

    // 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 TestStep dynamically

    // add a properties step
    testRunner.testCase.addTestStep( "properties", "another step" );

#### Fail the script step

    // fail randomly
    if( Math.random() > 0.5 )
       throw new Exception( "A random error has occured!" );

#### Read/set cookies

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 inludes 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" ))

### GroovyUtils

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, usefull for accessing data files in same folder
- `setPropertyValue( String testStepName, String propertyName, String value )` : sets the specified property value
- `expand( string )` - expands the specified Property Expansion string
- `getXmlHolder( 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 string

The 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 expresion.
- `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 expresion.
- `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 expressions
- `removeDomNodes( xpath )` - removes all DOM nodes matching the specified XPath expression
- `xml` : property containing the updated xml string
- `xmlObject` : property containing the parsed XMLBeans XmlObject for the xml string
- `prettyXml` : property containing the pretty-printed updated xml string
- `updateProperty()` : 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"] )

Next: Property Steps