Groovy is great for Agile development in general and testing in particular because:
- it has built-in support for the JUnit testing framework
- it has built-in mocking capabilities
- it provides a very expressive language in which to write tests which can utilise Closure syntax and Groovy's other features which support the creation of testing domain specific languages (DSLs)
- it's built-in AntBuilder support makes it easy to set up integration tests
This page explores testing features of Groovy and some other testing frameworks that you may sometimes
wish to use to complement Groovy's built-in capabilities.
Two main examples are used:
- A Stack Example
- An Item Storer Example
A Stack Example
Inspired by the RSpec stack example, suppose we want to test the following Groovy classes:
We can test this with vanilla Groovy using the following tests:
Of course, even within vanilla Groovy we have a few options. E.g., we could use no test class, just a script, in which case, the naming conventions required by JUnit 3.x (used above) wouldn't apply. Or, we could have used JUnit 4 and annotations to allow us to use alternate naming conventions for the methods. Alternatively, we could use a single test class with different test fixtures, e.g.
emptyStack. The other frameworks mentioned below allow additional possibilities for organising and naming our tests.
An Item Storer Example
Suppose we have the following Java interface (Groovy supports interface-oriented programming as well as dynamic programming using duck-typing and here we want to illustrate Java test/mock libraries later):
Now suppose we have an implementation method as follows:
For numbers, the
reverse() method will negate them. Thanks to duck-typing, other objects that we try to reverse will just call their respective types
reverse() method if it exists, e.g. so it will work for
Now suppose we make use of a reverser in some code we are trying to test.
We can integration test this class as follows:
Mocking Groovy Classes
The above integration tests exercise our class under test with the production
reverser in place. For this particular example, we might argue that such a test is appropriate and sufficient. However, in more complicated scenarios, the dependent collaboration class (
GroovyReverser in this case) might be difficult or expensive to construct. In those cases, we would want to replace it with a mock or stub. See Groovy Mocks for a definition of terms.
Here is how we would use Groovy's built-in mock support to test our class under test in isolation:
Note that we didn't need to do anything to inject our mocks into the class under test. Inside the
use method, all attempts to create a
GroovyReverser object will be replaced by a mock object. This also works for Java objects created by Groovy objects, as the following shows:
JavaReverser is a class that we have defined as follows:
Hmmm. Quite a bit longer than the Groovy version. But that's another story.
Testing Java classes which use other Java classes
Now, consider now the following Java class:
We now want to test this too and we want to use Groovy to write the tests. Unfortunately, Groovy's built-in mock support won't help us here. It doesn't allow us to test Java classes like this one as it relies on hooking into Groovy's object lifecycle mechanisms. Instead, we can use any of the available Java mocking packages such as the ones mentioned below.
Using Other Frameworks
Sometimes you may wish to consider complementing Groovy's built-in capabilities with one or more of the following frameworks: