Unit testing in Grails is currently implemented with Grails Testing plugin. The plugin provides unit
testing facilities through the GrailsUnitTestCase
class which offers a lot of useful methods for mocking
Grails-specific objects. This post demonstrates how some of these methods can be used to test Grails domain classes and
services.
The post is written for the Grails version 1.3.7
Domain classes & mockDomain
The GrailsUnitTestCase.mockDomain
is designed to replace implementations of the domain class methods. For instance,
it adds new save()
, get()
and delete()
implementations which do not persist an object state to a database,
instead they keep the object in the testing framework cache:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
As you can see, the mockDomain(Product, testInstances)
adds three product instances to the cache, so they can be
retrieved later with the get()
, or count()
. Also, since the Product
domain is mocked, the cache will be updated
instead of a database when the save()
method is called from the productService.saveProduct()
.
Constraints & mockForConstraintsTest
The GrailsUnitTestCase.mockForConstraintsTest
is another tool for testing domain classes, as you have already guessed,
this method should be used to test constraint declarations. The code below must be self-explanatory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Services & mockFor
The GrailsUnitTestCase.mockFor
came from Groovy, it is an all-purpose method that allows to create a mock for
any class. This makes it a perfect tool for replacing service class implementations:
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Here, the generateCode()
's behaviour is replaced using the demand
property of the control object:
1
|
|
where:
- mockControl - the control object
- demand - starts a new expectation
- foo - the name of the expected method
- (1..2) - the number of calls. If no range is specified, the default of "1..1" will be assumed
- {-> ...} - closure that provides a new method implementation
Logging & mockLogging
The testing plugin also allows to intercept log messages and redirect them to the output stream. This is done with the
GrailsUnitTestCase.mockLogging
method which replaces a log
property of a class:
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 |
|
This code results in the following output:
1
|
|
Conclusion
The rumors are that Grails 2.0 will provide mixin-based implementations of the testing facilities, which, of course,
would be much more appropriate for the framework. In the meantime, the GrailsUnitTestCase
already allows to create
perfectly fine, though a bit verbose, unit tests for the objects that are specific for Grails.