Tips & Tricks

PDF Print E-mail
User Rating:  / 43
Rate this article: PoorBest 
Download soapUI Pro trial

Here comes a collection of useful scripts for you, be sure to check back often as we will be adding new ones continuously, and if you have some cool scripts to share please mail them to us so we can add it!

1. Accessing Properties, Settings and Names

1.1. Get and Set properties

Getting properties from groovy is straight-forward; all objects that contain properties have a getPropertyValue / setPropertyValue methods. The following examples are from inside a Groovy Script step:

// get properties from testCase, testSuite and project
def testCaseProperty = testRunner.testCase.getPropertyValue( "MyProp" )
def testSuiteProperty = testRunner.testCase.testSuite.getPropertyValue( "MyProp" )
def projectProperty = testRunner.testCase.testSuite.project.getPropertyValue( "MyProp" )
def globalProperty = com.eviware.soapui.SoapUI.globalProperties.getPropertyValue( "MyProp" )

// setting values is equally straigh forward
testRunner.testCase.setPropertyValue( "MyProp", someValue )
testRunner.testCase.testSuite.setPropertyValue( "MyProp", someValue )
testRunner.testCase.testSuite.project.setPropertyValue( "MyProp", someValue ) 
com.eviware.soapui.SoapUI.globalProperties.setPropertyValue( "MyProp", someValue ) 

From inside a Script Assertion, you have to access testCase in another way:

def testCaseProperty = messageExchange.modelItem.testStep.testCase.getPropertyValue( "MyProp" )

Have a look at the TestPropertyHolder interface for digging into the object model.

1.2. Get and Set Settings

Global preferences can be set via the SoapUI.settings property, the different tabs have corresponding Settings interfaces in the com.eviware.soapui.settings package, each interface defines constants for each settings. So for example to set the SSL Keystore and password programmatically, you could call

import com.eviware.soapui.settings.SSLSettings
import com.eviware.soapui.SoapUI 

// set
SoapUI.settings.setString( SSLSettings.KEYSTORE, pathToKeystore )
SoapUI.settings.setString( SSLSettings.KEYSTORE_PASSWORD, keystorePassword )

// get
SoapUI.settings.getString( SSLSettings.KEYSTORE, "value to return if there is no such setting set" )

1.3. Project name

This is how to access the Project name from a Groovy Script TestStep:

testRunner.testCase.testSuite.project.name

(almost all items have a name property)

1.4. Test step name

Get the name of the step been executed:

context.getCurrentStep().getLabel()

1.5. Conditional inline property expansion

This is how you could conditionally expand a property in a request, or similar, based on the value of a third custom property. If the selection TestCase property has the value "selection" the TestCase property myFirstXMLSnippet will be expanded, else mySecondXMLSnippet will be expanded:

 ${= testCase.getPropertyValue( "selection" ) == "first" ? testCase.getPropertyValue( "myFirstXMLSnippet" ) : testCase.getPropertyValue( "mySecondXMLSnippet" )}


2. DataSources and DataSinks

2.1. Implementing Groovy DataSources and DataSinks

Here's an example Groovy DataSource to get you going:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectPath = groovyUtils.projectPath
def folderName = projectPath + "/testData"
def row = testRunner.testCase.testSteps["DataSource"].currentRow
def allFiles = []
new File( folderName ).eachFile() { file ->
   if( file.name =~ /.txt/ )
   {
      allFiles.add( file.name )  }
   }

if ( (row + 1) <= allFiles.size )
{
   // output to the TestStep property called inputData
   result["inputData"] = new File( folderName + "/" + allFiles[row] ).text
}

Here's an example Groovy DataSink :

// Write the response from the "Test Request: login" TestStep to a file
def currentUser = context.expand( '${#TestCase#currentUser}' )
def response = context.expand( '${Test Request: login#Response}' )
new File( "C:/Users/eviware/" + currentUser + "_response.txt" ).write( response )

// To use another charset than the default, do this instead:
// new File( "C:/Users/eviware/" + currentUser + "_response.txt" ).write( response, "UTF-8" )

2.2. Aggregating multiple DataSource rows to the same request

One way to do this is to use a Datasource + Datasource Loop with a Groovy step between which appends the Datasource elements to a property, and then use the property after exiting the loop.

def countryCode = context.expand( '${DataSource#CountryCode}' )
def countryName = context.expand( '${DataSource#CountryName}' )

def frag = context.expand( '${Properties#XmlFragment}' )

def newPropertyValue = '${frag}${countryCode}${countryName}'
testRunner.testCase.setPropertyValue( 'XmlFragment', newPropertyValue )

Thanks to M McDonald for this one!

2.3. Randomizing DataSource rows

There is no built in support for DataSources fetching random rows in SoapUI, but this can be achieved with some scripting. Structure your TestCase like this:

randomDataSource

The TestSteps should contain the following:

Original DataSource

A DataSource test step for the actual data that you want to randomize. Use this as you would normally.

Collect row
// create list if necessary
if( context["allRows"] == null )  context["allRows"] = []

// append current row from Original Source to allRows
context["allRows"] << context.expand( '${Original Source#output}' )
Original loop

DataSource Loop that loops to Collect row (Target Step) for each row in Original Source (DataSource Step).

Shuffle collected rows
Collections.shuffle( context["allRows"] )
Groovy DataSource
def row = testRunner.testCase.testSteps["Groovy DataSource"].currentRow

if ( row + 1 <= context["allRows"].size() ) 
{
    result["randomRow"] = context["allRows"][row]
}
Groovy DataSource loop

DataSource Loop that loops to the first test step using the random data (Target Step) for each row in Groovy DataSource (DataSource Step).

3. XML nodes

3.1. Iterate nodes

A common and equally straight forward task, use the GroovyUtils class to create an XmlHolder, which you can use for a variety of XML related activities:

// create groovyUtils and XmlHolder for response of Request 1 request
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( "Request 1#Response" )

// loop item nodes in response message
for( item in holder.getNodeValues( "//item" ))
    log.info "Item : [$item]" 

If the desired content is namespace qualified (very likely for SOAP responses), you need to define the namespace first. Continuoing from above:

// define namespace
holder.namespaces["ns"] = "http://acme.com/mynamspace"

// loop item nodes in response message
for( item in holder.getNodeValues( "//ns:item" ))
   log.info "Item : [$item]"

3.2. Count nodes

Use the GroovyUtils class to create an XmlHolder, which you can use for a variety of XML related activities:

// create groovyUtils and XmlHolder for response of Request 1 request
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( "Request 1#Response" )

def numberOfLinksInParagraphs = holder["count(//html/body/p/a)"]

3.3. Advanced parsing and updating

Please read XML Parsing in SoapUI (by Robert Nemet).

4. Access JMS headers

The example below sets the JMS header JMSCorrelationID to "foo4711" for myTestStep.

def myTestStep = testRunner.testCase.getTestStepByName("Some JMS TestStep")
def msgID = "foo4711"

myTestStep.testRequest.JMSHeaderConfig.messageSelector = "JMSCorrelationID = '${msgID}'"

5. Change a request XML from groovy

This example sets the password inside a request SOAP message:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )  

// get XmlHolder for request message def 
holder = groovyUtils.getXmlHolder( "login#Request" ) 

// change password using XPath 
holder["//username"] = "test"  

// write updated request back to teststep 
holder.updateProperty()
context.requestContent = holder.xml

5.1. Validate request XML against the WSDL

Add the following in a Script assertion

def project = messageExchange.modelItem.testStep.testCase.testSuite.project

def wsdlcontext = project.getInterfaceAt(0).getDefinitionContext() def validator = new com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator(wsdlcontext);

def errors = validator.assertRequest(messageExchange, false)

for( error in errors )   
  assert false

5.2. Remove empty XML elements from request

This functionality can actually be achieved by configuring the test step as shown in the following image:

Remove empty XML elements

But in some cases people want to then remove parent XML elements after empty elements are removed. That can be done with a event script for RequestFilter.filterRequest:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( context.requestContent )

// find end nodes that also only consist of whitespace
for( item in holder.getDomNodes( "//*[normalize-space(.) = '' and count(*) = 0]" )){
    item.removeXobj()
}
// update request and write updated request back to teststep
holder.updateProperty()
context.requestContent = holder.xml

6. Changing response before it gets validated

For example if you want to change all 555 to 444 in all response messages, proper way is to use RequestFilter.afterRequest event handler and add script:

if( request.response == null )
  return

// get response content
def content = context.httpResponse.responseContent

// manipulate content
content = content.replaceAll( "555", "444" )

// write it back 
context.httpResponse.responseContent = content

Now these changes will be picked up by assertions, too (read more at Custom Event Handlers).

7. Playback and MockService Control

7.1. Loop a sequence of TestSteps X times

A simple loop is easiest achieved by placing a Groovy Script TestStep after the last TestStep in the loop with the following content:

if( context.loopIndex == null )
   context.loopIndex = 0

if( ++context.loopIndex < 10 )
   testRunner.gotoStepByName( "Name of first TestStep in loop" )

This script first creates the loop counter in the context and then loops back until the value is 10 (think of it as a do...while loop)

7.2. Start and stop MockServices

This can come in handy both from the Project onLoad script (if you want to start your MockServices when the project is opened) or from a TestCase/TestSuite setup script (if you need the MockService running for your functional tests). Here from a TestCase setup script:

def runner = testCase.testSuite.project.mockServices["My MockService"].start()
context.mockRunner = runner 

The returned runner object is required to stop the MockService... so save it to the context and use it in the tearDown script:

context.mockRunner.stop()

Have a look at the WsdlMockService and the WsdlMockRunner classes for more methods and properties that might come in handy.

To start your mock services in the SoapUI project automatically on load, place the following code in: Project > "Load Script" tab

mockServicesCount = project.getMockServiceCount() 
for (i in 0..(mockServicesCount-1)) {
	project.getMockServiceAt(i).start();
	i++;
}

7.3. Simulate a delay for mock service responses

To simulate a delay between 0 and 10 seconds, add a “MockRunListener.onMockResult” event at project level with the following code:

sleep(new Random().nextInt(10) * 1000)

8. Logging results

8.1. Saving all TestStep's results into files

To save the result (request data, response data, response time, etc.) of every executed TestStep in a Project, create a Project EventHandler (Project Window > Events tab > Add new EventHandler) of type TestRunListener.afterStep with the following content:

filePath = 'c:/users/henrik/soapUI-results/'
fos = new FileOutputStream( filePath + testStepResult.testStep.label + '.txt', true )
pw = new PrintWriter( fos )
testStepResult.writeTo( pw )
pw.close()
fos.close()

8.2. Logging the result messages of all TestSteps in all failing TestCases

This is intended to run in a TestSuite Teardown Script.

for ( testCaseResult in runner.results )
{
   testCaseName = testCaseResult.getTestCase().name
   log.info testCaseName
   if ( testCaseResult.getStatus().toString() == 'FAILED' )
   {
      log.info "$testCaseName has failed"
      for ( testStepResult in testCaseResult.getResults() )
      {
         testStepResult.messages.each() { msg -> log.info msg }
      }
   }
}

Thanks to Finan for this one!

9. Determine whether a TestCase is run from the Command Line, as a LoadTest, etc.

if( com.eviware.soapui.SoapUI.isCommandLine() )
{
   log.info "This code is executed by Command Line SoapUI"
}
if( context.LoadTestContext != null )
{
   log.info "This code is executed from a LoadTest"
}

10. Use a JDBC Driver from inside a groovy script

If you want to do direct JDBC calls from a groovy script you first need to register the driver as follows

// register MySQL JDBC driver
com.eviware.soapui.support.GroovyUtils.registerJdbcDriver( "com.mysql.jdbc.Driver" )

(note that you still have to add the actual JDBC Driver jar to the bin\ext folder)

11. Access SOAP Operations / REST Resources

This example accesses SOAP Operations in the Sample Project.

import com.eviware.soapui.impl.wsdl.WsdlInterface
myInterface = (WsdlInterface) testRunner.testCase.testSuite.project.getInterfaceByName("SampleServiceSoapBinding")
myOperation = myInterface.getOperationByName("login")
myRequest = myOperation.getRequestByName("Request 1")

12. Add custom HTTP header to requests

Add “RequestFilter.filterRequest” event with the following example code:

def headers = request.requestHeaders
headers.put( "X-tokenHeader", "value" )
request.requestHeaders = headers

13. Encode attachments with Base64 encoding

Change the file path to one applicable

def inputFile = new File("C:\\Temp\\FileToAttach.txt").getText('UTF-8')
String encoded = inputFile.bytes.encodeBase64().toString()
return encoded

14. Generate a universally unique identifier

${=java.util.UUID.randomUUID()}

15. Run a TestCase located in another project

def prj = testRunner.testCase.testSuite.project.workspace.getProjectByName("ProjectName")
tCase = prj.testSuites['TestSuiteName'].testCases['TestCaseName']
tStep = tCase.getTestStepByName("TestStepName")
def runner = tStep.run(testRunner, context)
log.info ("runner status ....... : " + runner.hasResponse())