soapUI exposes a rudimentary "Extension API" for adding custom actions and listeners. ReadyAPI extends the API to allow all extension classes be created with Groovy in the soapUI Script Library with recompile support, meaning that extensions will be recompiled and instantiated when they updated without the requirement to restart ReadyAPI, making it extremely easy to develop new extensions (see below)
Initially two types of extensions are supported:
- Actions - custom actions can be associated with any ModelItem and will be shown on that items popup-menu
- Listeners - custom listeners "hook" into internal events and can be used for modifying requests, generating custom reports, logging statistics, etc..
Please Share!! any extensions you create that may be of use for others! Contact us and we will help you publish them on the soapUI and ReadyAPI web sites. Thank you!!
1. soapUI Actions
All popup menu actions are stored in a "SoapUIActionRegistry" and are initialized from a "soapui-action.xml" file included in the soapui-XXX.jar file. The actionRegistry can merge additional actions into the existing ones from external XXX-actions.xml files in a bin\actions folder under the soapUI installation. The actions.xml file has 2 parts: action definitions which specify action classes and give them an ID, and actionGroups which group actions for use with target ModelItems. The internal soapui-actions.xml defines a large number of actionGroups which are used for creating the existing popup-menus, external actions must be added to these to be displayed in soapUI.
Let's start with an example demo-actions.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tns:soapui-actions xmlns:tns="http://eviware.com/soapui/config">
<!-- defined action -->
<tns:action id="DemoAction" actionClass="soapui.demo.DemoAction"/>
<!-- add action to project popup -->
<tns:actionGroup id="EnabledWsdlProjectActions">
<tns:actionMapping actionId="DemoAction"/>
</tns:actionGroup>
</tns:soapui-actions>
and the corresponding DemoAction.java:
package soapui.demo;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.action.support.AbstractSoapUIAction;
public class DemoAction extends AbstractSoapUIAction
{
public DemoAction()
{
super( "Demo Action", "Demonstrates an extension to soapUI" );
}
public void perform( ModelItem target, Object param )
{
UISupport.showInfoMessage( "Welcome to my action in project [" + target.getName() + "]" );
}
}
Install as follows:
- Compile the above DemoAction.java and package it in a jar file
- Put the jar in soapui\bin\ext
- Put the demo-actions.xml in soapui\bin\actions
- Restart soapUI
That's it! You should see the following log info on startup:
10:09:20,484 INFO [SoapUI] Added [file:/C:/workspace/core/ext/soapui-demo.jar] to classpath
...
10:09:23,421 INFO [DefaultSoapUICore] Adding actions from [C:\workspace\core\actions\demo-actions.xml]
And your action will magically now appear at the end of the project popup:
2. Event Listeners in soapUI
Listeners can be used to listen in on a number of events "inside" soapUI.
Let's go with an example, create the following demo-listeners.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tns:soapui-listeners xmlns:tns="http://eviware.com/soapui/config">
<tns:listener id="DemoListener" listenerClass="soapui.demo.DemoListener"
listenerInterface="com.eviware.soapui.model.testsuite.TestRunListener" />
</tns:soapui-listeners>
and the corresponding DemoListener.java:
package soapui.demo;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.model.support.TestRunListenerAdapter;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
public class DemoListener extends TestRunListenerAdapter
{
private long startTime;
public void beforeRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
{
startTime = System.nanoTime();
}
public void afterRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
{
long endTime = System.nanoTime();
SoapUI.log( "TestCase [" + testRunner.getTestCase().getName() + "] took " + (endTime-startTime) +
" nanoseconds." );
}
}
Install as follows:
- Compile the above DemoListener.java and package it in a jar file
- Put the jar in soapui\bin\ext
- Put the demo-listeners.xml in soapui\bin\listeners
- Restart soapUI
IMPORTANT NOTE! your listener xml file should be suffixed with -listeners as in demo-listeners.xml
That's it! You should see the following log info on startup:
...
10:09:20,484 INFO [SoapUI] Added [file:/C:/workspace/core/ext/soapui-demo.jar] to classpath
...
10:22:14,968 INFO [DefaultSoapUICore] Adding listeners from [C:\workspace\core\listeners\demo-listeners.xml]
...
And when you run a TestCase you will get the following in the soapUI Log:
10:25:41,890 INFO [SoapUI] TestCase [TestCase 5] took 992305 nanoseconds.
The above listener will be instantiated for every TestCase in your workspace, if you instead want the listener to be created in a single instance add the singleton="true"
attribute to the listener configuration
3. ReadyAPI Extension Scripting
In ReadyAPI all the above extensions can be created in Groovy and loaded from the Groovy Script Library instead. ReadyAPI provides special utility classes that allows Groovy-extensions to be reloaded on modification so updates will be available without restarting (in most situations). When Groovy 1.1 is release with support for annotations, one will be able to create groovy extensions without any configuration files.
Lets create the above action and listener with Groovy instead; create the same config files but instead add the two following Groovy files to your script library:
DemoAction.groovy
package soapui.demo
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.support.UISupport
import com.eviware.soapui.support.action.support.AbstractSoapUIAction
public class DemoAction extends AbstractSoapUIAction
{
public DemoAction()
{
super( "Demo Action", "Demonstrates an extension to soapUI" )
}
public void perform( ModelItem target, Object param )
{
UISupport.showInfoMessage( "Welcome to my groovy action in project [" + target.name + "]" )
}
}
(note that groovy 1.0 does not fully support generics so we use the non-typed version of perform instead)
DemoListener.groovy
package soapui.demo
import com.eviware.soapui.SoapUI
import com.eviware.soapui.model.support.TestRunListenerAdapter
import com.eviware.soapui.model.testsuite.TestRunContext
import com.eviware.soapui.model.testsuite.TestRunner
public class DemoListener extends TestRunListenerAdapter
{
private long startTime
public void beforeRun( TestRunner testRunner, TestRunContext runContext )
{
startTime = System.nanoTime()
}
public void afterRun( TestRunner testRunner, TestRunContext runContext )
{
long endTime = System.nanoTime()
SoapUI.log.info( "TestCase [" + testRunner.testCase.name + "] took " + (endTime-startTime) +
" groovy nanoseconds." );
}
}
Upon startup you will see the following in the soapUI log:
...
11:15:59,000 INFO [SoapUIProGroovyScriptEngineFactory] Initializing scripts folder [C:\workspace\soapui-pro\scripts]
11:15:59,531 INFO [SoapUIProGroovyScriptEngineFactory] 2 classes loaded
11:15:59,531 INFO [DefaultSoapUICore] Adding listeners from [C:\workspace\soapui-pro\listeners\demo-listeners.xml]
...
11:16:03,109 INFO [DefaultSoapUICore] Adding actions from [C:\workspace\soapui-pro\actions\demo-actions.xml]
...
By default, ReadyAPI instantiates these classes only once at startup and will not check for updates. Specialized extension classes for this are available.. let's modify the above configuration files to make our extensions reloadable:
Change the demo-listeners.xml file to contain:
<tns:listener id="DemoListener" listenerClass="com.eviware.soapui.support.scripting.listeners.ScriptTestRunListener" groovyClass="soapui.demo.DemoListener" listenerInterface="com.eviware.soapui.model.testsuite.TestRunListener"/>
And change the demo-actions.xml file to:
<tns:action id="GroovyScriptAction" actionClass="com.eviware.soapui.support.scripting.actions.SoapUIScriptAction"/>
<tns:actionGroup id="EnabledWsdlProjectActions">
<tns:actionMapping actionId="GroovyScriptAction" name="Demo" description="Reloadable Demo Action"
param="soapui.demo.DemoAction"/>
</tns:actionGroup>
Restart ReadyAPI (restarts are currently always required for updated configuration files) and you will get the same log output as previously, only now can modify the DemoAction.groovy/DemoListener.groovy files without having to restart ReadyAPI.
The above examples are all included in the ReadyAPI distribution in the scripts/actions/listeners folders.