Working with Properties with Groovy
//Setting a user-defined property the "traditional" way:
context.setProperty("myVar1", "Value1")
//Setting a property using map syntax-- treating property names
//and values as key-value pairs:
context["myVar2"] = "Value2"
//Setting a property using simple dot notation:
context.myVar3 = "Value3"
//Get the "traditional" way:
log.info("Value of myVar2 = " + context.getProperty("myVar2"))
//Get using map syntax:
log.info("Value of myVar3 = " + context["myVar3"])
//Get using simple dot notation:
log.info("Value of myVar1 = $context.myVar1")
This produces the following output:
You can see all three methods for setting and getting properties are functionally equivalent to each other.
These aren't restricted to user-defined properties; Groovy lets you use the same shortcuts to work with objects' intrinsic properties-- the properties that are class members, typically accessed via their own "getter" and "setter" (sometimes called accessor and mutator) methods. For example, the WsdlTestCaseRunner class has a method called getResultCount(), which returns the number of step results returned in a test case run. You can access the same data using simple dot notation and map syntax:
//"Traditional" method to access result count
log.info(testRunner.getResultCount())
//Alternative ways to get the result count
log.info(testRunner.resultCount)
log.info(testRunner["resultCount"])
Closures
def logTCProp = {log.info("$it = " + testCase[it])}
Here we're defining a closure called logTCProp; its purpose is to take a test case property name (a string) and write the name and its value to the script log (note this closure should be run in a test case setup or tear down script, where the testCase variable is available). The keyword it serves as a placeholder for the argument passed in when the closure is called:
logTCProp('name')
This calls the logTCProp closure, passing in the string 'name' as its argument. When the closure is evaluated, 'name' replaces the it keyword; effectively, it becomes equivalent to the following:
log.info("name = " + testCase['name'])
The resulting output (for a test case named "ClosureExamples"):
The real power of closures is in their ability to be passed as arguments to certain methods (typically related to collections of data-- lists, for example). Here's an example using the each() method with a Groovy list of strings, using the logTCProp closure we defined previously as its argument:
def propList = ['name' , 'testSuite' , 'testStepCount']
propList.each(logTCProp)
First we define propList as a list of test case property names, then each() is called as a method of the list, with the closure passed in as its argument. Basically, each() ends up functioning like a for loop: the specified closure (the argument) is executed using each member of the calling list in turn as its argument. Compare it to:
for(prop in propList){
logTCProp(prop)
}
The resulting output (from the each() method and the for loop):
Another method that can take a closure as its argument is collect(). The collect() method can be used with closures that produce some output value-- as with each(), collect() executes a specified closure against each member of a list, but collect() puts the values output by the closure together into a new list. Here's an example that gets a test case's step results and puts their statuses into a list:
def returnStatus = {it.status}
def resList = testRunner.results
def statusList = resList.collect(returnStatus)
log.info(statusList.toString())
Example output:
You can save yourself even more typing by taking advantage of anonymous closures-- there's no need to name and define the closure separately from the method calling the closure; instead you can simply place the closure's code (braces and all) after the name of the method with which you'd like to use it. Here's the example I just gave rewritten using an anonymous closure:
def resList = testRunner.results
def statusList = resList.collect{it.status}
log.info(statusList.toString())
Note that returnStatus is no longer defined anywhere-- instead, its bit of code (
{it.status}
) is placed it after the call to the collect() method. Also note that there are no parentheses used with the method call (as we do when using a named closure)-- it's as if the braces around the code take their place.For more on working with Groovy, check out its official site (I recommend the "Beginner's Tutorial" section of the Getting Started Guide as a starting point).
No comments:
Post a Comment
Please be respectful of others (myself included!) when posting comments. Unfortunately, I may not be able to address (or even read) all comments immediately, and I reserve the right to remove comments periodically to keep clutter to a minimum ("clean" posts that aren't disrespectful or off-topic should stay on the site for at least 30 days to give others a chance to read them). If you're looking for a solution to a particular issue, you're free to post your question here, but you may have better luck posting your question on the main forum belonging to your tool's home site (links to these are available on the navigation bar on the right).