Why Test Engineers Should Learn Groovy

If you’re a Ruby programmer than, like me, you may have a healthy distrust of the bloated thing that is Java. That said, Java really does have a lot of good points and it would be silly for any tester to discount it. Well, more to the point, discounting Java, the language, for your test solutions may not be a problem; but don’t discount the JVM. There are other languages that run on it, Scala being one of them. Here I want to talk about a language that a Rubyist should feel right at home with: Groovy. So let’s learn to be Groovy.

Groovy is a lightweight, low-ceremony, dynamic, object-oriented language that runs on the JVM, follows Java semantics, and extends the JDK. A key part there is that Groovy runs on the JVM you already have installed, starting from 1.4 up to the most recent. You can write Groovy in the same IDE you use for Java development, such as TextMate, IntelliJ, Eclipse, whatever. You can also deploy Groovy to the same application servers you already have in production.

Groovy was expressly designed to be something that Java developers would want to use. It’s important to keep in mind that Groovy is Java. I say that because there are other languages that run on the JVM and those languages are often different languages entirely. For example, consider JRuby or Jython. The goal of these two languages is to get Ruby code or Python code, respectively, running on the JVM. The point of Groovy, on the other hand, is to integrate with your existing Java code. Groovy and Java are so much alike that you can take a file (say, HelloWorld.java) and convert it a Groovy file (HelloWorld.groovy) and you will have a perfectly valid — and executable — Groovy file. That most certainly is not the case with JRuby or Jython. That little trick won’t even work in all cases with Scala.

Let’s Get Groovy

Here I’m going to assume you have a version of Java installed (1.5 or greater) as well as Groovy. This is one of those things where if you are going to be experimenting with JVM-based languages, you really should know how to get those things on your operating system of choice. So I won’t cover that here.

To start things off, create a file called learning.groovy. Put the following in it:

This is basically a Java program at this point, although you’ll note that unlike Java, Groovy does not require you to name the top-level class as the same name as the file. Nevertheless, you could compile this with the javac compiler without problem. However, try running this command instead:

groovy learning

You’ll see that Groovy did not need a compile step. You can run Groovy logic as scripts rather than as compiled classes. So does this mean Groovy is an interpreted language? Nope. In fact, Groovy is compiled into bytecode just like Java. The groovy command you just ran did two things: it compiled your code and then executed it. Okay, if that’s the case, where is the .class file? In this case, the bytecode is created in memory and discarded at the end of the execution. Now, to be sure, you can compile your Groovy logic if you wish and run it on the JVM, keeping your .class file around as well. First compile it:

groovyc -d classes learning.groovy

To prove to yourself that this will run on the JVM, try to run it. If on Windows, you’ll do something like this:

java -cp %GROOVY_HOME%/embeddable/groovy-all-2.1.6.jar;. Greetings

On *nix systems, the only variation is the separator and how you indicate environment variables:

java -cp $GROOVY_HOME/embeddable/groovy-all-2.1.6.jar:. Greetings

Obviously the above presupposes you set up an GROOVY_HOME environment variable. The reason you have to include that jar is because Groovy logic relies on the GroovyObject. But, again, note here that you are doing everything just as you would with a Java program in a Java environment, including the use of classpaths.

Now modify your program so that it looks like this:

This is the same program again but with the class and method definitions commented out. Unlike Java, Groovy does not require that all logic be within a class. Also note that System.out has been removed from in front of the print() and println() method calls. Finally, note that semicolons, which are optional in Groovy, have been removed.

From now on, if you want to see that each of the changes works, just run the following command:

groovy learning

So now that you’ve seen that, remove all the commented lines so that your logic looks like this:

This will let us focus on the specifics rather than having to avoid looking at boilerplate we don’t need in the first place. As an example of one such specific, change your code to this:

This is the same program but with a lighter ceremony form of the for loop which, in this new case, uses a range. This shows you one way that Groovy allows for a bit of a nicer syntax than Java. If you have worked with Python or Ruby before, that range concepte should be familiar.

Let’s try another variation. Change your code to this:

Here instead of using a range in a for loop, this version uses a convenience method defined on java.lang.Integer called upto(). The “it” in the above code represents the index value through the loop. How this works is that the upto() method accepts a closure as a parameter. If the closure expects only one parameter, you can use the default name “it” for that parameter. You could also use “it” as part of the string, like this:

This is pretty much the same as the last example but uses the “it” inside the string. The $ in front of the variable “it” tells the method print() to print the value of the variable instead of the literal characters. This is how you can embed expressions within strings, which is another way of saying string interpolation.

Note too that the {} around expressions are optional if the expression is a simple variable name or a simple accessor to a property. So the above call to print() could have been done like this:

Groovy is Pure

You will find that Groovy is a pure object-oriented language, unlike Java, which is why you can call a method like upto() on an integer literal. Another variation on this technique is the following:

The only difference here is that I’m using the times() method but, again, note that I’m calling it directly on an integer literal. To those coming from Ruby, this will be nothing new. This kind of freedom allows you many possibilities. Here is yet another variation:

Here I’m using the step() method. The above gives the same output as you’ve been seeing; but you could change the second parameter to change the step count, such as changing it to 2 so that the range is counted up by values of 2.

So just to recap a bit, here’s what I started with:

That’s pretty much Java for you. To compare with Groovy, here’s one variation that’s quite a bit more concise:

Incidentally, if you want to know how this kind of thing is done in Groovy — and how you can do it yourself — here’s an example. Let’s say I want to add the traditional check for whether a word is a palindrome and I want that to be a method that can be called on any string. Easy enough:

Here the ‘delegate’ refers to the object that the method — isPalindrome — was called on. You could test that this is working as such:

Here the variable phrase is the delegate. Another common example is adding a method to numbers, such as calculating the percentage. Here’s an example:

Then to calculate 10% of 100,000 you could do the following:

As you can see, Groovy is about providing a lot of convenience methods and dynamic functionality. Part of this allows you to avoid boilerplate code when it should not be necessary. One example is checking for null. You have to do that a lot in Java. For example, if I want a method that does nothing more than reverses a string, I should at least check if the string passed in is null. Here’s how I can do that in Groovy:

The safe-navigation operator — ?. — in the above method calls the method or property only if the reference is not null. This negates the need to check for null as you would have to in Java, where you would have to use this line instead:

To test out that it works, try these statements:

Groovy is Concise

Groovy allows you to dramatically reduce the amount of code you would normally write in Java. Let’s consider a simple class in Java:

I could use that bloated mess with Groovy just as it is. To do that I could just rename Person.java to Person.groovy and I’m all set. Or I could use Groovy to help me trim down on that. Here’s an example of idiomatic Groovy code:

That’s all you have to do. It does the same as the Java code above. Am I sure about that? Well, let’s test it out. If you were to create the above Person.groovy code, compile it and then investigate the internals with javap, using these commands:

groovyc Person.groovy
javap -private Person

What you will see is something like this:

PS C:\Crypto\Projects> javap -private Person
Compiled from "Person.groovy"
public class Person implements groovy.lang.GroovyObject {
  private java.lang.String firstName;
  private java.lang.String lastName;
  ...
  public java.lang.String getFirstName();
  public void setFirstName(java.lang.String);
  public java.lang.String getLastName();
  public void setLastName(java.lang.String);

Notice how you have getters and setters there that you did not define? By default, in Groovy all objects are public. All attributes are private. There are getters and setters for each field, as you can see in the javap output, but these methods are autogenerated in the bytecode rather than the source code. That means that what I did in Groovy is an immediate replacement for the Java class. Compile it down to bytecode, and the Groovy version is indistinguishable from its Java counterpart.

What you have with Groovy is Java stripped down to its essence; it’s the core of Java but with the syntactic noise removed. What you have done is reduced complexity and improved the signal-to-noise ratio. When you are creating test solutions that kind of thing really matters.

Continuing this theme, the traditional “hello world” is a perfect example. Here’s what it must look like in Java:

Here it is in Groovy:

But how can that be the same? It’s not even in a class! Well, Groovy scripts implicitly create the public class line as well as the public static void main() line, leaving you with the above for the drop-in replacement to the more verbose Java. Again, to test that do these commands:

groovyc HelloWorld.groovy
javap -private HelloWorld

You will see this:

public HelloWorld();
public HelloWorld(groovy.lang.Binding);
public static void main(java.lang.String...);

The Groovy example does exactly what the Java code does but with a fraction of the lines of code.

I really want to hammer this point home so here’s another comparison for you. Consider this Java code:

Here I’m using java.lang.Process to interact with a system-level process. Isn’t Java fun? Here’s a way I can do that exact same thing in Groovy:

With Groovy, I can simply use the execute() method that has been defined on the java.lang.String class. Yet with this I’m still using Process and the JDK in this Groovy code. When I called the execute() method on the instance of String, Groovy created an instance that extends java.lang.Process, just like the exec() method of Runtime did in the Java code. When I call text, I’m calling the Groovy-added method getText() on the Process to read the process’s entire standard output into a String. If you want to verify what I just said, run this:

Note that if you are on Windows and running a shell command, you may have to indicate the cmd as such:

No matter how you slice it, this is a lot easier than the Java version.

One final example: reading through a file line-by-line. Here’s the Java version:

And here’s how you do that in Groovy:

But — wait. Is Groovy handling all those exceptions as well? Yes, in fact it is. Remember before how I showed you that null was automatically checked for. Groovy also will automatically handle exceptions based on the types that it is working with. This is an area you can experiment with to see how it works.

What this is showing you is that Groovy can be used as a drop-in replacement for Java and that’s the case without changing any of the semantics of the Java language. So if you are test solution developer in a team of Java developers, you can use a language that has the dynamic power of Ruby, but with the buy-in from Java developers who will be able to run code directly as part of their normal course of operations. While the semantics of Java stay the same, Groovy certainly introduces new language constructs that are different from Java as you’ve seen. For example, that File.eachLine is a closure, which is basically a different way to iterate over a file without using java.util.Iterator.

There is so much more I could talk about with Groovy. As with the Ruby language and, to a lesser extent Python, the dynamic nature of Groovy allows it to create fluent logic that allows you to create domain specific languages in a way that Java simply cannot. One of the key elements of Groovy are closures, very similar to blocks in Ruby.

I believe this is important for test solution developers because you can utilize the Java platform — i.e., the JVM — but you can also look beyond the Java language to languages that are lightweight and that can make you more productive and allow you to create much more interesting solutions to testing problems.

Hopefully this got you thinking about Groovy a bit more. For me, it was a language that was barely on my radar largely because I tended to avoid all things Java for developing test solutions.

Share

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.
This entry was posted in Career, Learning. Bookmark the permalink.

5 Responses to Why Test Engineers Should Learn Groovy

  1. Raúl says:

    Great article. I’ve tried all yor examples, and now I want more. Time to get Groovy in action (Second edition). Do you now any other good source to learn groovy?

    Thank you.

    Raúl

    • Jeff Nyman says:

      Glad you liked the article and thanks for the comment.

      I’m looking at potentially getting back into Groovy a bit. I’ve experimented here and there with Scala and Clojure. Clojure is probably the one I like the best, mainly because I like Lisp-based languages, but Groovy is definitely more akin to the dynamic languages I tend to run with. Truth be told, I don’t really like any of the JVM-hosted languages all that much but that’s only because I’m so mired in how I do things in Python, JavaScript and Ruby. The only reason I stick with them at all is because it’s undeniable that the JVM is a powerful platform to run on.

      I do recommend the book “Making Java Groovy”, which is pretty decent.

  2. Jared says:

    The main question I have is how Groovy manages libraries?  That is, what’s the alternative to ‘gem install …’.  I would argue this is where most of Ruby’s productivity for testers comes from.

    • Jeff Nyman says:

      I have yet to get too much back into Groovy but I think, in general, you would follow the JVM-style dependency management systems, such as using Gradle or Maven to handle getting the libraries you need in place. And I completely agree that the Ruby style gem system (similar in concept and execution to the Node npm package system) leads to much more productivity at that level. Then again, being fair to both ecosystems, once I have the libraries I need — or at least the supporting elements to get them — that problem starts to normalize a bit. However, even as I say that, I know I would much rather deal with the RubyGems type system any day.

  3. sandeep says:

    A great introductory article Jeff.

    You have provided me lot of motivation to explore Groovy more. It looks like Groovy could be very helpful tool because for testing I use Selenium with Java and other tools like jmeter, SOAPUI supports Groovy.

     

Leave a Reply

Your email address will not be published. Required fields are marked *