Recently about Groovy
On my current project we have been involved in converting some of the hundreds of manual tests that are run by our Test Team every release into a suite of automated Selenium RC tests.
During the course of this adventure my crew found several instances where XPath and native JavaScript were not sufficiently expressive to find elements in some of our more complicated interfaces.
Since our web app uses the Prototype/Scriptaculous JavaScript framework we wanted to find a way to make the locating power of Prototype available within Selenium RC.
We developed approaches for both Selenium 0.9.2 and Selenium 1.0.3 (which had better programmatic support for adding JavaScript user extensions to Selenium).
Selenium 0.9.2
Selenium RC provides the capability to add "user extensions" to augment its JavaScript core.
See http://seleniumhq.org/docs/08_user_extensions.html for detailed information on how to set this up.
We wrote the following user-extension.js file:
Selenium.prototype.setupProtoypeJS = function() {
id = selenium.browserbot.getCurrentWindow().$;
css = selenium.browserbot.getCurrentWindow().$$;
}In our code we have a base class for all our test cases. To this we added our own waitForPage() method:
public void waitForPage() {
selenium.waitForPage('60000')
proc.doCommand('setupPrototypeJS', [])
}Thus every time the page reloads (which clears the JavaScript context) we call waitForPage() and this command is re-executed. It creates two global variables (id and css) and binds them to Prototype's $ and $$ functions respectively.
Note: The reason we choose id and css instead of $ and $$ was that Groovy considers $ in Strings to be a special character and we would have had to escape it each time it was used.
The Prototype selectors can now be used in Selenium RC like this:
selenium.click("dom=id('foo')")
selenium.click("dom=css('.bar')")
selenium.click("dom=css('span.foo a.baz')")Note: You still have to specify the dom locator type so Selenium RC will know to execute your locator string as JavaScript.
Selenium 1.0.3
In more recent version of Selenium RC the project added the setExtensionJs() method. This allows you to set extension JavaScript programmatically prior to starting the selenium client:
selenium = new DefaultSelenium(...)
selenium.setExtensionJs('...')
selenium.start()
This made it much easier to implement our Prototype bindings. The only trick was that the JavaScript seems to be executed prior to having access to a page context and is also only executed once. This required us to take a different approach.
We created id and css as global functions instead of variables. This allowed us to defer accessing the current window until the functions were actually invoked.
selenium.setExtensionJs('''
id = function(value) {
return selenium.browserbot.getCurrentWindow().$(value);
}
css = function(value) {
return selenium.browserbot.getCurrentWindow().$$(value);
}
'''); Note: The above code snippet is written in Groovy which allows multiline Strings.
The Prototype selectors are used in Selenium RC like before:
selenium.click("dom=id('foo')")
selenium.click("dom=css('.bar')")
selenium.click("dom=css('span.foo a.baz')")I would be interested in hearing feedback from anyone who has a chance to use this technique!
So I stumbled across Griffon not too long ago:
http://griffon.codehaus.org/
It is a new project on Codehaus.org whose unique aim is to bring the Grails framework and way of doing things to the desktop application development world. I am not yet convinced this is a good idea, but since I still have many fond memories of Swing development I was intrigued to see what MVC for a desktop application might look like.
Like Grails, Griffon is built on Groovy, so if you are not familiar with Groovy you might want to take a look at:
http://groovy.codehaus.org/
On my current project we are starting to develop a suite of Selenium tests to help automate manual tests our test team are performing every release. Anyone who has used Selenium will probably agree with me that it can be finicky. When I write a selenium test I find myself frequently having to tweak a little XPath here, rerun the whole test, tweak a waitForCondition() there, rerun it again, etc.
Inspired by this drudgery I wrote a Griffon app that would give me a sandbox in which I could play with Selenium live instead of in the context of a test.
If you are interested in Griffon, I will walk you through some of the basics and you can see what you think. If you just want the app I wrote feel free to download it. I hope it will ease some of the pain of using Selenium!
Installing Griffon is not too hard. Download it, unzip it, create a GRIFFON_HOME system variable, and then glom $GRIFFON_HOME/bin to your PATH.
Like Grails, Griffon provides an application scaffolding script. Simply type griffon create-app and you have a skeleton for an application.
Of interest to this little tutorial are the models, views, and controllers folders, as well as lifecycle and conf.
MODEL
A Griffon model is just a POGO. It does not have to inherit from any particular class. It is associated with a controller and a view via the naming convention.
So for example, here is the model from my Selenium Console project:
class SeleniumConsoleModel {
@Bindable String host
@Bindable String port
@Bindable String command
@Bindable String baseUrl
@Bindable boolean serverRunning = false
@Bindable String scriptSource
@Bindable String scriptResult
@Bindable boolean enabled = true
}Griffon will automatically associate this model object with a view named SeleniumConsoleView and a controller named SeleniumConsoleController.
Note the use of the @Bindable annotation. This is a very interesting feature that will be put to good use in the view.
VIEW
Griffon uses Groovy SwingBuilder syntax to create a view. Here is a snippet from the SeleniumConsoleView:
application(title:'Selenium Console', pack:true, locationByPlatform:true, iconImage: imageIcon('/griffon-icon-48x48.png').image,
iconImages: [imageIcon('/griffon-icon-48x48.png').image,
imageIcon('/griffon-icon-32x32.png').image,
imageIcon('/griffon-icon-16x16.png').image]
) {
panel() {
borderLayout()
panel(constraints:CENTER) {
borderLayout()
panel(constraints: NORTH, border: raisedBevelBorder(), background: Color.DARK_GRAY) {
flowLayout(alignment:FlowLayout.LEFT)
panel(opaque: false) {
button("Start Selenium", actionPerformed: controller.&startSelenium, enabled: bind { model.enabled }, visible:bind(source:model, sourceProperty:'serverRunning', converter:{ !it }))
button("Stop Selenium", actionPerformed: controller.&stopSelenium, enabled: bind { model.enabled }, visible:bind(source:model, sourceProperty:'serverRunning'))
}
...
By making good use of Groovy's dynamic features, the SwingBuilder syntax allows you to declaratively build your layouts. Each "method call" (such as panel() or button() is actually interpreted by methodMissing and the corresponding Swing component is constructed and added in whatever scope it occurs. The named parameters correspond to properties of the component which can be set inline.
A useful reference for all the valid named parameters that can be called on each component:
http://groovy.codehaus.org/Alphabetical+Widgets+List
A closure containing any subcomponents to be added can be passed in as well, allowing you to anonymously nest components inside of each other.
Two properties are injected into the scope of the view: model and controller, allowing you to access them where appropriate.
BINDING
Groovy / Griffon allow you to "bind" one property to another. This mechanism acts like an action listener, when a property changes, any property that is bound to it also changes. This is extremely useful because you can bind GUI widgets (such as a checkbox or a testarea) to your model. As the user interacts with the GUI, the state of the GUI is automatically captured on your model object.
This can also work in reverse. You can set portions of your GUI to respond to changes in your model object.
A recent project started out life as an all-Java project that used Maven as the build tool. Initially we used Atlassian Clover to measure unit test coverage. Clover is a great product for Java code, but unfortunately it only works with Java code because it works at the Java source level. (This was the case as of Spring 2009, and I haven't checked since then.) As we started migrating existing code from Java to Groovy and writing new code in Groovy, we started to lose data about unit test coverage because Clover does not understand Groovy code. To remedy this problem we switched from Clover to Cobertura, which instruments at the bytecode level and thus works with Groovy code. Theoretically it would also work with any JVM-based language but I'm not sure whether or not it could handle something like Clojure or not.
In any case, we only cared about Groovy so Cobertura was a good choice. With the Cobertura Maven plugin we quickly found a problem, which was that even though the code coverage was running, the reports only showed coverage for Java code, not Groovy. This blog shows you how to display coverage on Groovy code when using Maven and the Cobertura plugin. In other words, I'll show how to get Cobertura reports to link to the real Groovy source code in Maven, so you can navigate Cobertura reports as you normally would.
The core problem is pretty simple, though it took me a while to figure out how to fix it. Seems to be pretty standard in Maven: I know what I want to do, but finding out how to do it is the really hard part. The only thing you need to do is tell Maven about the Groovy source code and where it lives. The way I did this is to use the Codehaus build-helper-maven-plugin which has an add-source goal. The add-source goal does just what you would expect; it adds a specified directory (or directories) as a source directory in your Maven build. Here's how you use it in your Maven pom.xml file:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/groovy</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
In the above code snippet, we're using the "build-helper-maven-plugin" to add the src/main/groovy directory. That's pretty much it. Run Cobertura as normal, view the reports, and you should now see coverage on Groovy source code as well as Java.
My current project (a web application) has a module that is almost entirely written in Groovy. Note: We are using the latest version 1.6.5 of Groovy.
In one of the methods we had some logic similar to the following:
def myMethodToProcessTheList(def listOfThings) {
if (listOfThings && listOfThings.size < 0) {
//Do my logic}
}When the above code is run using Java 5 everything works wonderfully. However when we pushed the code out to our server running Java 6 we got an interesting error stating that it couldn't compare java.util.ArrayList to java.lang.Integer.
The problem is actually that the size method needs the parens after it (Note: The Groovy docs actually do state that methods with at least ONE param can omit the parens). I realize now that it would make sense that parameter-less methods would need parens because how else would Groovy distinguish between methods and property accessors? I did find one forum post that indicated that in Groovy, lists have special properties that act like the spread-dot operator. That is why the listOfThings.size returned the ArrayList instead of a number.
So why does this work in Java 5 but not Java 6? That is a great question, one of which I really don't have a definitive answer. I'm not completely sure if this purely a Java 5/Java 6 difference or simply a difference between the IBM Java 5/Java 6 JVM.
If anyone has a theory as to why it would work one way on Java 5 and the other in Java 6, I would love to hear it.
Example the first: Generics at the end of a line:
def list = [1,2,3] as List<Integer>
println list
If you try to compile this in Groovy it will give you the error message: 'unexpected token: println', however this:
Gives the expected output.def list = [1,2,3] as List<Integer>;
println list
Example the second: Ambiguous Closures
{-> assert GroovyClosureTest == owner.getClass() }()
{-> assert GroovyClosureTest == delegate.getClass() }()
I don't think you'd really ever need to do something like this, but a closure can be defined and called on a single line. Because of Groovy's special closure parameter syntax (e.g. list.each() {} being synonomous with list.each({})) the compiler thinks I'm passing the second closure into the first as an argument. Again a semicolon is needed to seperate the two lines:
{-> assert GroovyClosureTest == owner.getClass() }();
{-> assert GroovyClosureTest == delegate.getClass() }()

