Align Automated Test Language with Development Language?

I pose the title of this post as a question. My focus here is as a tester who sometimes has to work with Java shops that really don’t want to involve their developers with Ruby or some other dynamic language. I, on the other hand, do not want to give up the benefits of a dynamic language when I develop my automated test solutions. Yet I do want to involve the developers in test automation. I don’t want to use JRuby necessarily because it’s really just a complicating element of running Ruby on the JVM. What I want is to utilize the Java platform (the JVM) but look beyond the Java language to languages that are lightweight but also dynamic. Groovy is proving to be that.

Here I’m not going to prove why Groovy is a good solution for test languages. The same reason that Ruby is good is the same reason that Groovy is good. However, you may have to convince Java developers to give Groovy a shot. I’ve found many Java developers tend to not be aware — or are only very peripherally aware — of some of the cool things available on the JVM platform. So the focus of this post is showing a little bit about how Groovy works like Java, but with some simplifications.

Why Dynamic Groovy?

Before getting to into this, why do I focus on the dynamic languages? Well, there’s a reason why the Ruby community has put much more focus on testing than the Java community. The Ruby language makes writing testing tools fun and easy. It’s the reason why tools like RSpec and Cucumber (both written in Ruby) have served as a de facto standard for the evolution of test tools in other languages. The dynamic aspects of the Ruby language make a lot possible and I even cover why test engineers should learn Ruby just because of this fact.

So I focus on the dynamic languages because such languages have the ability to extend a program at runtime, including changing types, behaviors, and object structures. With dynamic languages, you can do things at runtime that static languages do at compile time. You can even execute program statements that are created on the fly at runtime. The flexibility of dynamic languages gives you the advantage of evolving programs as the applications execute, which is something I’ve found very powerful when creating test tools that have to rely on a variety of situational concerns and circumstances. This is, in fact, the basis of code synthesis — essentially the in-memory creation of code at runtime. The code is synthesized based on the flow of logic through your application and becomes active just as it is needed.

Okay, so why not do this with Java? Well, the simple reason is that you can’t. Java has certainly improved its support for metaprogramming over the course of years but it doesn’t hold a candle to a language like Ruby. Many people are putting a lot of hope on Java 8, just as they did with Java 7. But the situation right now is that you can use the somewhat complex and not-so-flexible Java together with heavyweight tools (like AspectJ or Spring) to try to develop some of the more dynamic test solutions. Or you could move on to using dynamic languages such as Ruby that were object-oriented and had metaprogramming capabilities built in. It really is sort of an either-or.

Yet it’s really not an either-or proposition if you put your emphasis on the JVM (as platform) rather than on Java (as a language). Dozens of languages can run on the JVM: Groovy, JRuby, BeanShell, Scheme, Jaskell, Jython, Scala, JavaScript, Clojure, and others.

Functional languages, like Clojure or Scala, are gaining a lot of ground due to their focus on functional programming. A meme making the rounds is that, when used correctly, dynamic languages, the functional style of programming, and metaprogramming capabilities are the keys to being effective and efficient. I’m not sold yet on the functional style of programming part of that yet — mainly because I’m still learning it — so my focus is on the dynamic language and the metaprogramming. My background is Python and Ruby and, because of that, Groovy is what I have begun to settle on.

Groovy Java

To play along, create a file called comics.groovy. To start off put the following in place:

Note that I’m using a package. Yes, Groovy, like Java, can use a packaging mechanism. If you were to compile the above script with this

groovyc -d classes comics.groovy

You would end up with this structure:

.
|___classes
    |___com
        |___testerstories
            |___comicdepot
                |___Comic.class

Something else to note is that I have not declared anything public or private. Groovy most certainly has access modifiers like Java, such as public, private, and protected. So why aren’t I using them? The reason is that classes in Groovy are implicitly public if you don’t provide an access modifier. This contrasts with Java where classes are package-private unless you specifically say otherwise.

Incidentally, what “package-private” means is that if you leave the access modifier off of a class, attribute, or method, then other classes in the same package or direct sub-classes in another package can access your own directly.

Likewise, attributes in Groovy are implicitly private if you don’t provide an access modifier whereas methods in Groovy are implicitly public if you don’t provide an access modifier are.

To show that this is working, you can add the following outside the class definition in your groovy file:

Just to make sure you see what I see, the following should be the output of those statements:

private java.lang.String Comic.series
private java.lang.Integer Comic.issue
public java.lang.String Comic.toString()

You might ask why Groovy does this implicit access modifying, particularly since it breaks the semantics with Java? It’s done largely for convenience. Certainly it’s not going out on too much of a limb to say that a Java convention is that classes are public and attributes are private. Groovy simply encodes that convention, freeing you up from having to specify it every time. Less typing is good. Less typing means more productivity. And, yes, I know people will say, “Well, IDEs generate that stuff for you anyway.” I’ll just say I’ve never been a fan of having another tool write code for me, particularly when that code is not necessary. No doubt this comes from by background with Ruby and Python where you tend not to rely on IDEs to do a lot of work for you.

Another thing are those getters and setters that Java folks have to put in place so much. Yes, you can rely on an IDE to do it for you — which has long covered up the inefficiency of having them in their in the first place. In Groovy, every attribute gets a matching set by default. You could determine this for yourself using javap to look at a compiled version of your class. (I show an example of using javap this way in my previous post regarding Groovy basics.) For now let’s test this out via code. Put this in your script:

This is showing you the public interface of the class. Because this is the public interface, it means you would not see any private methods. With the above statement, you’ll see a large list, but somewhere in there you’ll see these:

public void Comic.setVolume(java.lang.Integer)
public java.lang.Integer Comic.getVolume()

public void Comic.setSeries(java.lang.String)
public java.lang.String Comic.getSeries()

public void Comic.setPublisher(java.lang.String)
public java.lang.String Comic.getPublisher()

public void Comic.setIssue(java.lang.Integer)
public java.lang.Integer Comic.getIssue()

public void Comic.setTitle(java.lang.String)
public java.lang.String Comic.getTitle()

Let’s test if this code actually works though. Put the following outside of your class definition:

What this shows you is that the getters and setters are working and thus have been defined for you. Even with that, I’ve pretty much done things the Java way there. Yet another way Groovy cuts down on visual clutter is a little syntactic shortcut for when you are dealing with class attributes. Put the following in place:

Here where I call comic.volume, that’s like me calling comic.getVolume(). What I’m doing is dealing directly with the comic’s volume, rather than calling a getVolume() method on a class of Comic so that I can get an Integer value returned to me.

So, again, just to repeat what is for me an important point: instead of your IDE generating getters and setters for you, the Groovy compiler does it. And what’s better: it keeps them out of your face. If you do need to generate a specific getter or setter, then you would just specify that one. I would argue that makes it so much more clear as to what you are doing in your code. You are only going to include the getters or setters that you want to specifically override.

Since I have overridden the toString() method, you can get a string representation of the comic:

You’ll note that the toString() method is pretty simple. It doesn’t explicitly return anything with a return statement, as you would have to do in Java. In Groovy the value of last expression in a method will be what is returned to a caller. So this means I could put a specific string that I want. For example, let’s say I want the output to be the format of “series volume issue (title)”. Further, I want to make sure I leave room for issues up into the hundreds so that 1 is rendered as 001. I can change my toString() method to return this:

This however will not work as-is because that call to .padded is method that I want to be called directly on any integer. That means I have to use the metaclass aspects of Groovy. At the top of your script, and outside of the class definition, put the following:

With the data that I set earlier for the attributes, when calling “println comic” I would get this output:

The Avengers v1 001 ("The Coming of the Avengers")

What you might notice there is that in that code in toString() I used a triple-quoted string, which will certainly be familiar to you if you’ve used languages like Python. Such a string is sometimes called a heredoc or a docstring. Basically, though, it’s a triple-quoted string that allows you to not have to escape quotes inside of it.

What if I don’t want the getters and setters? After all, that’s a reason that you might not write them in Java. In Groovy, you can declare a field as private in an explicit way. That will mean getter and setter methods are not created. However, does that mean I can no longer get and set? Is the private field no longer accessible? Well … add this to your class:

Normally, of course, a date would be in some sort of date object, but here I’m being simple for the illustrative purposes. With the above code in place, the following logic will generate an error:

Yet, you will find that these do work just fine:

So that’s interesting, right? What’s happening here is that in the first case, the methods were not generated because of the private access modifier. However, the field is still directly accessible as the last bit of code would show you. So in effect Groovy is letting you ignore the private access modifier. Technically you can avoid the private modifier in Java as well, but it’s much harder.

For some people, this really bothers them. For others, it doesn’t. You have to decide that for yourself. What I can say is that when writing test solutions, this has never been an issue for me. It’s certainly made me a more careful programmer and a more disciplined one, I would argue.

Moving on from that, you can also get all of the properties of a given object as such:

That will show you that the elements of the object are treated as properties. Why that matters is because you could also use a very Java-like method to get property information:

You can also use something like this to set a property:

What about creating the object? I already did this in a very basic way with the example so far, simply by using the default constructor. However, by supporting named arguments and a variable-length argument list, you can instantiate your class in a variety of ways based on your needs. So here are some examples:

These two examples show that you can supply the fields in any order that you want since the variables are named. And since they are named, that means the order does not matter. Given that these are variable arguments, you can also include as many or few as you want, such as:

You can also provide what is often called optional parameters but what are really better thought of as default parameters. So, for example, let’s say that most of the comics you are going to be creating objects for will be for DC. That means in most cases you will want the publisher property to be “DC”. In that case, you can add a constructor to your class definition like this:

Note that with the example I’m showing here, having that constructor alone would probably not do you much good if you also plan to use the named parameters. I’ll let you experiment with that to see why but if you’ve worked with any object-based language, the reason will probably be clear If not, just try a few example statements that I’ve already provided you and see what you observe.

Testers: Use Groovy in a Java Shop?

What I hope this post showed you is that using Groovy for your object-based considerations is really not that much different than Java. What Groovy provides is simply more convenience by convention. This is the kind of stuff that I think you may need to show Java developers who are not aware of Groovy but don’t want to work with test solutions written in other languages, like Ruby.

One thing I didn’t touch on much here is that, in fact, using Groovy doesn’t have to be any different than using Java. Once a class written in Groovy is compiled, it looks no different from a class written in Java. Put another way, when Java is running classes, it will not be able to distinguish Groovy classes from Java classes. This is because it’s all just bytecode to the JVM. Likewise, Java classes can look and execute just like Groovy classes even when being run from Groovy as opposed to Java.

As a final point, someone might argue: “Well, so what if the developers don’t want to use Ruby or Python? Isn’t that the choice of the test team?” Yes, it is — or, rather, it can be. But getting the developers excited about working with the test team can be a huge plus, not to mention the added benefit of a whole set of new eyes on the test solution code as well as possibly a set of experienced hands to help out. This last point can be particularly helpful if the current test team lacks programming skills. Further, this alignment of test code with development code does give you more options for potentially having the test solution code directly work with the application code.

As readers of this blog will likely know, I wrote my own version of a Cucumber clone called Lucid as well as a browser execution library called Symbiont. Both of those are Ruby-based solutions and I will likely never port them to Java. However, as I embark on a new phase of my career with a company in Chicago, I look forward to investigating the possibilities of those tools being ported to Groovy.

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 Automation. Bookmark the permalink.

Leave a Reply

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