soapUI Pro Holiday Goodies - Event Handlers and JDBC Connections
Digging further into the list of extra features in soapUI Pro reveals support for Event Handlers and improved handling of JDBC Connections. Let's have a look at both of these and how they can be used both on their own and together to provide some very handy functionality.
Quick and Easy Event Handlers - soapUI Pro
soapUI has had the possibility of registering custom listener classes for quite some time, but doing so is not the easiest of things (see soapUI Extensions). The new Event Handlers mechanism in soapUI Pro basically allows you to create these listeners from inside soapUI in "no time at all," making it really easy to customize test-execution related behavior. Let's dive right in and create our first handler that will modify outgoing request messages (a better rationale will follow!).
Start by opening the project view (here I'm going to use the trusty old Sample Project included with soapUI) and select the Events tab:
On the top is a table containing the Event Handlers defined for your project, the bottom area contains a script editor for the currently select handler. Press the "Add" button in the toolbar and select RequestFilter.filterRequest, which is an event in the RequestFilter interface, called for each outgoing request (internally soapUI has a bunch of filters for adding headers, security info, processing properties, etc.. all in the com.eviware.soapui.impl.wsdl.submit.filters package).
The problem we want to solve here is this:
Strangely enough, some web services out there expect a specific namespace prefix to be used in the request XML (often "SOAP-ENV"). From an XML-standard-point-of-view (my favorite..), the prefix could be any valid name, for example "thisisnotasoapmessage" or perhaps "soapenv", which incidentally is what messages generated by soapUI get. What we would like is to replace the "soapenv" in our requests with "SOAP-ENV", allowing us to test the not-so-standards-conforming web service. Using our filterRequest handler, this is easily done; enter the following code in the script editor for your filterRequest event:
context.requestContent = context.requestContent.replaceAll
( "soapenv", "SOAP-ENV" )
(obviously a bit crude, but good enough for now.. ).
The Handlers tab thus contains:
If we now open a request editor and send the request
we'll see in the Raw tab of the Request editor (which shows the raw data of the last sent request) that the message actually sent was:
You can also check the http log at the bottom of the soapUI window:
Mission accomplished! Before we look at another more advanced example (logging requests to a database), let's have a quick look at the new JDBC Connections feature.
The Art of JDBC Connections and JDBC Wizards - soapUI Pro
In soapUI Pro there are two places where JDBC connections are used; JDBC DataSources and JDBC DataSinks. Both of these allow you to configure the JDBC Connection string by hand, an art mastered only by a select few, or to manage them on the Project level, which doesn't require you to recreate them whenever you might need one. On top of that, a bunch of related improvements/features are available:
- Wizards for generating connection strings with preconfigured (and configurable) templates for most common databases (check the JDBC Driver Properties tab in the Global Preferences to see which ones are included)
- Wizard for generating simple SELECT / Stored Procedure calls when configuring a JDBC DataSource
- Wizard for generating UPDATE statements when configuring a JDBC DataSink
- DataSource/DataSink extensions for using a project level JDBC Connection
- Extended GroovyUtils with methods that allow you to use Project-level JDBC connections from your scripts
Let's have a look at how the last one of these can be used in an Event Handler (as described above) to log all your TestStep results during a LoadTest to a database for analysis, which is not as uncommon as you might think. In the example I'm going to set up a local MySQL database with just one table for holding TestStep results, the schema for the table being as follows (very denormalized for clarity):
CREATE TABLE `db_soapui`.`tb_loadtestlog` (
runindex` INTEGER UNSIGNED NOT NULL,
teststep` VARCHAR(50) NOT NULL,
type` VARCHAR(20) NOT NULL,
`starttime` INTEGER UNSIGNED NOT NULL,
`timetaken` INTEGER UNSIGNED NOT NULL,
`status` VARCHAR(10) NOT NULL,
`threadindex` INTEGER UNSIGNED NOT NULL
With this data we can do quite a bit of analysis after a long-running LoadTest (over the weekend perhaps!?).
After creating the database/table/user in MySQL (I'll leave that to you), let's go back to soapUI Pro and select the JDBC Connections tab in Project window for the project containing our LoadTest (empty to start with), and press the add-button. After specifying a name you will prompted for Driver and related properties:
In Select the MySQL JDBC driver (don't forget to add the MySQL JDBC Driver jar file to the soapuiprobinext folder) and add the connection info, test it to make sure it is working with the "Test Connection" button in the toolbar;
Now to our Event Handler; switch to the Events tab and create new handlers for the following events (all in the LoadTestListener interface):
- LoadTestListener.beforeLoadTest - to establish the Database connection and prepare an insert statement
- LoadTestListener.afterTestStep event (which will be triggered for each TestStep executed during our loadtest).
- LoadTestListener.afterLoadTest - cleanup!
Ok, let's do these one at a time, first to prepare the statement we will use for the insert (to minimize its impact on performance), this goes into the LoadTestListener.beforeRun script:
( "com.mysql.jdbc.Driver" )
def groovyUtils = new com.eviware.soapui.support.GroovyUtilsPro( context )
log.info "Creating DataSet for LoadTest logging"
context.groovySql = groovyUtils.getGroovySql( "LoadTestDB" )
context.dataSet = context.groovySql.dataSet( "tb_loadtestlog" )
Then the actual afterTestStep event which logs the step:
runindex : runContext.TotalRunCount,
teststep : testStepResult.testStep.name,
type : testStepResult.testStep.config.type,
starttime : testStepResult.timeStamp,
timetaken : testStepResult.timeTaken,
status : testStepResult.status.toString(),
threadindex : runContext.ThreadIndex
And then some cleaning up in afterLoadTest:
log.info "Closing connection used for LoadTest logging"
if( context.groovySql != null )
Very straight forward as you can see; we are using the GroovyUtilsPro class to get a groovy Sql object for our Project Connection and then using the Groovy DataSet object to do the actual insert (for performance reasons a prepared statement should probably be used instead). The Events tab now looks something like the following:
Now let's run a simple LoadTest to see what we get; I'm going to run the sample LoadTest in the Sample Project but increase the number of threads to 5 (which is going to give a number of errors since the MockService included in the Sample Project isn't thread-safe); after running the LoadTest window looks as follows (as you can see the groovy log contains some output from our event handlers):
Looking good! Now lets go into the standard SQL Query tool in MySQL and fire off some queries:
- The number of results per TestStep and status
- The average, standard deviation and variance for all requests and statuses
soapUI Event Handlers and JDBC Connections - Conclusion
I hope you agree that Event Handlers are a powerful and simple way of extending/tailoring the behavior of your tests/requests/etc. to your specific needs, and the JDBC connection functionality will definitely simplify JDBC-related testing efforts; now you have even more reasons to go Pro :-)