Groovy is the scripting language used in soapUI. Running on top of the Java Virtual Machine, it essentially extends and in some ways simplifies Java. In these posts, I may discuss concepts as Java concepts, but they apply to Groovy as well. However, keep in mind that much of the actual syntax you'll see here is specific to Groovy and will not work in Java (for example, lines of code in Java generally require a terminating semi-colon; Groovy script does not, and the examples here reflect that).
SoapUI supplies multiple components for adding Groovy to a project; these include Groovy Script test steps, Setup and Teardown scripts at the test case and test suite levels, and Groovy Script assertions. For our first example, we're going to use a single Groovy Script test step. Start soapUI and create a new project, giving it any name you'd like (there's no need to associate it with a web service at this point). Create a single test case with a single Groovy Script step; again, the names aren't important. Alternatively, you can download an empty shell project here and import it into soapUI.
Enter the following lines in the main window of your Groovy Script step (be sure to end each line of code with a return):
def myVar = 40 + 2
log.info(myVar)
log.info(log.class)
myVar = myVar - 1
log.info(myVar)
Click the run button at the top of the step window; you should see something like this in the Log Output panel:
It's spectacularly unimpressive, I know, but it illustrates a couple of key concepts. Let's go line by line:
def myVar = 40 + 2
This line illustrates two key concepts: declaring (basically, creating) a variable and assigning a value to a variable. A variable is essentially a named placeholder for some data-- by associating the data with a variable, you can reference the data via the variable name. When you need to create a new variable for use in your script, you can precede it with Groovy's def keyword-- you can think of it as being short for "define"; in this case we're creating a new variable called myVar. Note that I wrote you can precede it with def; it's not actually necessary to do so, but you'll probably see it used in example Groovy scripts elsewhere (including the soapUI site).
You may understand intuitively what the rest of this line does: it evaluates the statement on the right-hand side of the equal sign, summing 40 and 2, then applies (or assigns) the result (42) to the variable myVar on the left-hand side. In subsequent lines in our script, we can use myVar to represent the value 42... which is exactly what we do in the next line:
log.info(myVar)
This line prints the value of our variable myVar to the log window. Like myVar, log is a variable; unlike myVar, however, it was never explicitly created in our script. The log variable is one of several special variables in soapUI provided for convenience; it's made available automatically-- no need for declarations or assignment statements as with myVar. Built-in variables are indicated at the top of the Groovy Script step window ("Script is invoked with log, context, and testRunner variables"). Perhaps more importantly, while myVar represents a simple number (specifically, an integer), log represents an object-- a topic which warrants some extra attention as a core concept in Java/Groovy and many other programming languages.
Objects bundle together related data and functions in a meaningful way. As an example, consider a program that simulates a race between a number of cars. Keeping track of all the requisite information directly (each car's speed, acceleration, location, direction, etc.) could get unwieldy. With an object-oriented approach, however, we could create a special "car" data type; each of our simulated cars would be an instance of this data type, and each would be responsible for keeping track of its own information.
In Java, this data type definition or template is called a class. In this example, we might create a class called Car that has properties corresponding to speed, location, direction, etc. Additionally, we might create accelerate() and decelerate() functions (called methods when they're part of a class) that, when called, change the speed property accordingly. Each of our simulated race cars would be a Car object-- each would have all the properties of the Car class we defined, but have its own values for those properties. Additionally, each could call the accelerate() and decelerate() methods independently, affecting only its own speed property.
So, let's go back to the second line of our script with this extra information about objects:
log.info(myVar)
log is a variable corresponding to an object of the Logger class. The Logger class has a method, info(), that prints its argument (the data provided between its parentheses-- in this line of code, myVar) as an INFO level message in the log-- consequently, it prints the value 42. Note the syntax used to call an object's method (sometimes called dot notation): object.methodOfObject([argument(s)]). Note that some methods may take no arguments, in which case they have empty parentheses.
Moving on to line 3:
log.info(log.class)
This illustrates more dot notation. Once again, we're calling log's info() method, but this time we're using dot notation to get the class property for log and passing that as the argument to the info() method (the output confirms Logger is indeed log's class). Note the dot notation syntax for getting an object's property: object.propertyOfObject.
The next line is:
myVar = myVar - 1
This line may look odd-- even incorrect-- at first, with myVar on both sides of the equal sign, but it's perfectly valid and illustrates the way assignment statements are interpreted from right to left. Before this line is processed, myVar has a value of 42. The assignment statement evaluates the expression on the right-hand side of the equal sign first, subtracting 1 from 42. The result (41) is then assigned back to myVar. Note that the def keyword is not used here (compare this to the first line of the script)-- remember, def is only used at the time of a variable's creation; we're not creating myVar here, we're just changing the value it holds. Its new value is printed to the log in the last line:
log.info(myVar)
I'll try to cover the built-in context variable in a later post, but the testRunner variable is worth a quick look now. It references a soapUI runner object, which controls test execution and provides access to test results. The testRunner variable (and the analogous runner variable at the test suite level) can also serve as an entry point to get to other key soapUI objects. Enter and run the following code in your Groovy Script step:
def myTestCase = testRunner.getTestCase()
log.info(myTestCase.getName())
def myTestSuite = myTestCase.getTestSuite()
log.info(myTestSuite.getName())
The output:
Here we step up through the project tree, calling the getTestCase() method of the built-in testRunner variable to get a test case object corresponding to our test step's parent test case (assigned to the variable myTestCase), then use that test case object's getTestSuite() method to get a test suite object (assigned to myTestSuite).
That's it for now. You can explore some of soapUI's other classes in my posts on scripting objects-- you can find the post on the WSDLTestSuiteRunner class here, for example. For further reading, I also suggest the Object-Oriented Programming Concepts section of the Java Tutorials.
Helped a lot.. thanks :)
ReplyDeleteHi,
ReplyDeleteLooks Great!!!.
Could you explain the difference between 'Context' and 'testRunner' variable? and in which situation these needs to be used?
The built in testRunner variable handles test case execution; it has methods to get information about the test run (getTestCase, getTimeTaken, getResults, getStatus, etc.) and methods to control execution (gotoStep, runStep, etc.).
DeleteThe context variable provides access to properties and settings associated with a test run (via the setProperty and getProperty methods, for example). The properties you can set and get with the context variable include user-defined properties.
Am cleared. Thank You!.
DeleteWoo! thanks a ton Mike Sweeney for sharing this out, seriously it helped me a ton to understand what exactly I need to do nxt/ Keep Up the good work!!
ReplyDeleteThanks for this blog!
ReplyDeleteThank you! I have done greate job. You helped me a lot:)
ReplyDelete