Rupert Anderson's Blog

Mainly SoapUI, API, Open Source stuff and Elite Dangerous!

R2-Using SoapUI Groovy Grape dependencies

Scenario

If you want to use a Groovy or Java library that isn’t bundled with SoapUI, then the standard way is to add it to /bin/ext and restart SoapUI, as per Recipe R1. A slick alternative approach is to use the Groovy Grape dependency manager to add Maven repository artefacts as part of your Groovy Scripts on-the-fly!

Why bother?

There’s no compelling reason to use Grape over the standard way to include dependencies. However a different approach can sometimes present its own opportunities, some differences and possible advantages are:

  • Grape dependencies can be added at runtime without a restart.
  • Grape driven scripts are self contained and document their own dependencies.
  • Grape dependencies are managed and centralised by Groovy rather than SoapUI (see the More section).
  • Ease of use – there’s no need to manually download or package Grape dependencies.

Prep

Recipe Test Version Info:
SoapUI 5.2.1 (standard distribution / installer)
O/S: Windows 10
Java: Bundled JRE

Other: ivy-2.1.0.jar,ivy-2.4.0.jar,jsoup-1.9.2.jar,jsoup-1.10.1.jar

Project Setup
To try this out, we just need somewhere to run a Groovy script within SoapUI e.g. a Groovy TestStep.

Steps

1.Create A Groovy script with unresolved dependencies
Create a script that needs a dependency that SoapUI doesn’t already have in its /lib folder. In this example, I picked a script that requires libraries from the HTML parser JSoup. The script just parses an HTML string and extracts the anchor tag and displays it in a popup (once we satisfy all its dependencies).

import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element

def html = "<p>An <a href='http://rupertanderson.com/'><b>example</b></a> link.</p>"
Document doc = Jsoup.parse(html)
Element link = doc.select("a").first()

log.info link

2. (Optional) Test that the dependency is initially unresolved
As a test to make sure that the dependency doesn’t already exist within SoapUI’s classpath, run the above script to verify that the required imports are not resolved. You should see a SoapUI Error popup containing something like:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Script2.groovy: 3: unable to resolve class org.jsoup.nodes.Document @ line 3, column 1. import org.jsoup.nodes.Document ^ org.codehaus.groovy.syntax.SyntaxException: unable to resolve class….

3. Add Ivy jar
Unfortunately we can’t use Grape without first adding the Ivy jar. At time of writing the latest version of ivy is ivy-2.4.0.jar, this can be obtained from:

https://mvnrepository.com/artifact/org.apache.ivy/ivy/2.4.0

For classpath reasons this needs to be added to /lib (not /bin/ext/) otherwise you will see the error:

SoapUI missing Ivy dependency

3. Add a Grape statement

To get the script working, we need to use Grapes to include the JSoup dependency. Again, Maven Central can help us, as it provides a useful Grapes tab with the syntax we need:

// https://mvnrepository.com/artifact/org.jsoup/jsoup
@Grapes(
@Grab(group='org.jsoup', module='jsoup', version='1.10.1')
)

Then paste this in above the imports like so:

@Grab(group='org.jsoup', module='jsoup', version='1.10.1')
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element

def html = "<p>An <a href='http://rupertanderson.com/'><b>example</b></a> link.</p>"
Document doc = Jsoup.parse(html)
Element link = doc.select("a").first()

log.info link

4.Run the script successfully!
Run again, and you should see the anchor tag from within the html variable extracted and output in the log:

<a href="http://rupertanderson.com/"><b>example</b></a>

More

Local Repository

If you were wondering where SoapUI stores the locally cached artefacts when they are downloaded, the default location is:

${user.home}/.groovy/grape 

If you have Groovy installed, then typing the following in a shell:

grape list

Will give you a list of all artefacts cached in the above location.

For configuration options please see:
http://docs.groovy-lang.org/latest/html/documentation/grape.html#Grape-Advancedconfiguration

Feature Request

If you like using the Grape functionality and would like to see Grape dependency management added as part of the standard SoapUI product, then maybe vote for this feature request:

https://community.smartbear.com/t5/SoapUI-Feature-Requests/Adding-Groovy-Grape-dependency-management-out-of-the-box/idi-p/130390

Links

  • For more JSoup examples see https://jsoup.org/cookbook/

R1-Developing and using custom Groovy libraries In SoapUI

Scenario

So maybe you’ve built up some useful Groovy code for over time that you use again and again, spread across your projects, but would rather manage it from one place? If so, this recipe shows how you can create and import them via jar files so that you can reuse them from SoapUI objects like Groovy TestSteps, Setup/Teardown Scripts and Script Assertions.

Why bother?

  • This way of packaging your Java/Groovy code promotes reuse and can ease the maintainability of your commonly used test code.
  • It is possible to use these libraries to override existing SoapUI code/functionality i.e. create patches.
  • Whilst various recipes in the SoapUI Cookbook show how to use prebuilt Java/Groovy libraries, I felt this was a valid recipe and building block in its own right.

TIP: Quick Start – People who already have a suitable Java/Groovy library and just want to know how to use it in SoapUI, can jump in at step #6

Prep

This recipe uses Groovy and Gradle (v2.12) to compile and package the example Groovy class as a jar file. If you haven’t got Gradle, please refer to http://www.groovy-lang.org/download.html and https://docs.gradle.org/current/userguide/installation.html

For mac/linux I used SDKMAN! (http://sdkman.io/) e.g.

sdk install gradle
sdk install groovy (This is optional, useful if you want to run some Groovy without SoapUI)

Steps

1.Create the following directory structure

soapuilib/src/main/groovy/custom

2.Get some Groovy code

For this example, I have knocked together a simple script to generate sequential ids. It may be of little practical use, but I wanted something with a simple public static method to call. Since the method is static, there will be no need to instantiate the class before calling it in step #8.

 
package custom 

import java.util.concurrent.atomic.AtomicLong 

public class SequentialIdGenerator { 
   public static final long counterSeed = 1000 
   public static final String prefix = "id"
   private static AtomicLong counter = new AtomicLong(counterSeed) 
   
   public static String nextId() { 
     return prefix + counter.incrementAndGet() 
   } 
} 
  • create the above script as a text file called SequentialIdGenerator.groovy
  • copy it to soapuilib/src/main/groovy/custom

3.Create Gradle build script

For this part, there are plenty of options to build the code and package it, such as Maven, Ant or just running the right shell commands! The following minimal Gradle script allows us to compile and package the code as a jar in one easy statement.

apply plugin: 'groovy'

version = '1.0'

jar {
   classifier = 'library'
   manifest {
      attributes 'Implementation-Title': 'SoapUI Sample Groovy Library', 'Implementation-Version': version
   }
}

repositories {
   mavenCentral()
}

dependencies {
   compile 'org.codehaus.groovy:groovy:2.1.7' //Matches Groovy in SoapUI 5.2.1
}

  • Create the above Gradle script as soapuilib/build.gradle
INFO: Groovy Version – (At time of writing) The current version of Groovy is v2.4.6, but SoapUI 5.2.1 ships with Groovy 2.1.7. If you try to compile with a Groovy version 2.3+ and use it with SoapUI, you will see an error popup and log message in like ‘org/codehaus/groovy/runtime/typehandling/ShortTypeHandling‘ – see http://glaforge.appspot.com/article/groovy-2-3-5-out-with-upward-compatibility for more details and options. Basically, you can still use the latest Groovy version, but will need to include an additional groovy-backports-compat23 dependency!

5.Compile it & Create jar file

Now we’re ready to use the Gradle script to compile the sample script from step #2 and package it as a jar file.

  • Open a shell/command prompt at soapuilib/
  • gradle clean build jar

You should then see output like:


tests-MacBook-Pro:soapuilib test$ gradle clean build jar
:clean
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 5.499 secs

This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.12/userguide/gradle_daemon.html

and our new library jar file created under the directory:

soapuilib/build/soapuilib-1.0-sample.jar

6.Add jar file to SoapUI

To make our new Groovy library jar available for use in SoapUI, it should be added in SoapUI Home under the following external library directory:

SoapUI ext Directory

Or the Windows equivalent e.g. C:\Program Files\SmartBear\SoapUI-5.2.1\bin\ext

7.Verify jar file is imported

When SoapUI is restarted, you should see the following log entry indicating that the jar file has been successfully added to the SoapUI classpath:

SoapUI ext Lib Loaded
8.Call the code

Our SequentialIdGenerator has a public static method nextId() that we can call, so to do this we can either import the class (Example 1)  or just prefix the class with its package (Example 2). See below:

  • Example 1 – Call from Groovy TestStep:
import custom.*

log.info SequentialIdGenerator.nextId()

Gives output like:


Thu May 12 16:49:20 BST 2016:INFO:id1001

  • Example 2 – Call from Property Expansion:

${= custom.SequentialIdGenerator.nextId()}

More

This section may evolve over time e.g. include details of further use-cases and examples. Anything you’d like to see, please ask!

Links

No links yet.