Beginning soapUI Scripting 1: Variables and Objects

This is the first of what I hope to be several posts about scripting in soapUI intended for beginners with little to no prior knowledge of Java or Groovy.  While they won't make you an expert, of course, I hope they'll give you enough information to get you on your way quickly.  This particular post will look at a couple of fundamental concepts in Java (and by extension, Groovy), including variables, objects, methods, and dot notation.  These explanations are pretty simplified for the sake of brevity, focusing more on a conceptual understanding than technical details, so I recommend checking out some of the material covered in my post on Java learning resources to dig a little deeper on your own.  The tutorials use soapUI itself, so there's no need to download anything else (I'm assuming you already have soapUI installed).

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.

Sikuli Script: Troubleshooting Problems with Scripts

One of Sikuli's appealing features is its relatively straightforward concept; ironically, that can make it all the more puzzling when things aren't working quite the way they should-- you can see your button right there on the screen, so why can't Sikuli?  This post has a couple of tips for new users for troubleshooting common script problems.

Note: as of this writing, the latest version of Sikuli is version 930, available in Windows as a set of files to be unzipped over the previous version, version 905.  Version 930 includes some significant fixes; if you're experiencing issues and using version 905, I'd recommend upgrading to version 930 as a first step.

If Sikuli can't find a graphic pattern:

1) Be sure to check any FindFailed error messages carefully.  I know, I know-- that may sound obvious, but when you're knee-deep in a scripting session and you've already worked through half a dozen "FindFailed" errors in the last hour, you may see the seventh pop up in Sikuli's log and immediately assume it's the same as the others.  A case in point from my own personal experience: after troubleshooting for some time to figure out why Sikuli wasn't finding a match for my graphic pattern, a closer inspection of the FindFailed error revealed that Sikuli wasn't looking for a graphic pattern at all-- for some reason it was looking for text (treating my pattern file's name as a string).  Among other things, a FindFailed error can also indicate a problem finding a png file in its expected location on disk.

2) If you're looking for the pattern in a defined region (as opposed to a search on the entire screen), make sure the region covers the intended area and fully contains the pattern you're looking for; one way to check this is by calling the highlight() method on your region-- e.g., my_defined_region.highlight(2). You can remove the call later on once you've finished debugging.

3) Don't be stingy with wait times.  Sikuli can interact with an application much faster than a human, and that's not always a good thing.  In some cases it may not find a pattern simply because it hasn't had time to draw completely (in response to some previous action).  Use a simple wait() statement to give the screen, region, etc. more time to draw before proceeding to the next step.

If Sikuli incorrectly identifies a match:

1) A mis-click near a pattern (close but not centered on it) may stem from re-drawing and or re-sizing a window or components in a window. Consider a scenario where Sikuli is waiting for a button to appear onscreen; as soon as it appears it registers the match.  Subsequently, the window finishes drawing, during which the placement of the button is adjusted to make room for other components.  Sikuli doesn't recognize this change in the button's location-- as far as it's concerned, the button is still where its pattern was first detected, and that's where Sikuli will try to interact with it.  Possible solutions in this case include inserting a fixed (designated in seconds) wait() statement or using another pattern as a cue to Sikuli that the screen has finished drawing.

2) If Sikuli keeps matching a pattern to items other than the one you're actually trying to isolate, first make sure your pattern is "focused"-- you generally want to avoid any nondescript surrounding white space that doesn't help Sikuli differentiate it from similar regions.  You can also increase the similarity setting for the pattern to require a closer match.  With your script loaded in Sikuli, bring up the application screen where a match for your pattern should be found and click on the pattern in your script, launching the Pattern Settings dialog.  The Matching Preview tab shows the current screen, highlighting any regions that match your pattern-- if you adjust the Similarity slider, the preview automatically updates to reflect the new value.  Yet another solution: limiting your search to a specific region around your target, excluding other potential matches outside the region.


The Matching Preview tab of the Pattern Settings dialog

For scripting issues not necessarily related to finding pattern matches, the popup() method can be used as a poor man's break point for debugging.  For example, you can use it to pause your script and print out the value of a counter variable in a for loop, a value evaluated in an if statement, etc.  The method can be removed from your final script once you've finished troubleshooting.

Finally, when all else fails or you're seeing completely inexplicable issues, save your work, shut down Sikuli, and check for any orphaned processes (in Windows, these appear as javaw.exe instances) before restarting.  I've seen scenarios where a script didn't seem to shut down properly (particularly when execution was interrupted with Alt + Shift + C) and behavior becomes flaky and unpredictable when I attempt to re-run the script or run another script.  Clearing out these orphaned processes and re-starting Sikuli sometimes helps in these cases.

For Beginners: Java Learning Resources

I've published a few posts on using Groovy in soapUI; as much as I'd like to believe my directions and writing are so clear that no further knowledge is required, I know that's probably not the case-- at the very least, a basic understanding of objects, variables, and other Java programming concepts are necessary, which means that readers who are genuinely new to scripting may have difficulty following some of the material in the posts.  I do want this blog to be a resource for absolute beginners; I may tackle a Groovy tutorial in future posts, but for the time being I thought I'd recommend a few resources for learning Java that I've found helpful.

A logical first step, of course, are the Java Tutorials available online and for download in multiple formats (HTML, mobi, and epub) on Java's home site here.  For beginners or near beginners, the Getting Started, Learning the Java Language, and Essential Java Classes tutorials are recommended.

For third-party publications, I've looked at three notable books on Java, each of which uses a different approach to learning the language.  Learn to Program with Java by John Smiley (Osborne/McGraw-Hill, 1st Edition - 2002) has a very gentle learning curve and an interesting framing premise: the book purports to follow an introductory Java class (taught by the author himself) as they work through creating a practical working Java application.  Head First Java by Kathy Sierra and Bert Bates (O'Reilly Media, 2nd Edition - 2005) takes a more irreverent approach, trying to inject a bit of humor into the topic.  Ultimately, it covers more material than the Smiley book, albeit at a faster pace with a more challenging learning curve.  Finally, there's Bruce Heckel's Thinking in Java (Prentice-Hall, 4th Edition - 2006); coming in at a breezy 1150 pages, this book is pretty in-depth, going beyond the language and syntax to explain what goes on "under the hood" in a Java program-- memory management, the timing of the creation of objects, etc.  This book covers everything you probably wanted to know about Java-- not to mention a lot of stuff you didn't know you wanted to know.  Generously, Mr. Heckel makes the 3rd edition of the book available for free online at his company's (MindView, Inc.) website here.  As I said, all of these books take very different approaches; if possible, try looking at a few sample pages of each to see which best matches your personality or learning style.

If you prefer learning via video, I highly, highly recommend Stanford University's Programming Methodology lecture series available on iTunes U.  Comprised of video recordings of an introductory computer science course, this one is easy to overlook due to its relatively nondescript title.  In fact, while the course is primarily intended to be an introduction to programming concepts in general (hence the name), Java is the language chosen to illustrate those concepts, so it turns out to be a pretty decent introduction to Java specifically.  The lecturer, Professor Mehran Sahami, seems to have genuine affection for his job-- he injects his lessons with plenty of humor and explains things in engaging, easily understandable terms.  My primary issue with the series is the video quality; while it's not a major problem most of the time, text from presentation slides is occasionally hard to read.  The series is popular on iTunes; I hope Stanford might consider re-recording the class sessions in higher quality in the future, although I wouldn't want anything else to change about them.

Of course, this is the tip of the tip of the tip of the iceberg of what's out there, and Java's ubiquity means the list of materials (free and otherwise) will only grow.  Perhaps you have some favorites of your own; are there any Java learning resources you'd recommend to others?