Using Mock Annotation and mockFor in Grails Unit Tests

More and more often, when reading documentation, I find myself thinking of the lyrics from The Kinks song Lola:

… well I’m not dumb, but I can’t understand…

Too often, I find the documentation to be sparse and the examples included too simple. A gap exists from reading the documentation, looking at the included examples and transposing that unto real-world problems that are not quite that simple.

My current project at work is using Grails 2.0.x and I was very glad to see that it included a whole collection of unit testing mixins. In particular, there were three things I wanted to start using right away when testing a service:

  • TestFor annotation
  • Mock annotation
  • Defining mocks and stubs programtically

Now although that the documentation is indeed sparse, it turns out that it actually is very concise. The documentation states that:

Most testing can be achieved via the TestFor annotation in combination with the Mock annotation for mocking collaborators

@Mock([Book, Author, BookService])

followed by

The Mock@ annotation creates mock version of any collaborators. There is an in-memory implementation of GORM that will simulate most interactions with the GORM API. For those interactions that are not automatically mocked you can use the built in support for defining mocks and stubs programmatically. For example:

def control = mockFor(SearchService)
control.demand.searchWeb { String q -> ['mock results'] }
control.demand.static.logResults { List results ->  }
controller.searchService = control.createMock()

I first really understood what it said after playing around with it for a while. It is here that some real-life examples along with a few words of explanation would have been very helpful. So here goes with an example from the real world – hopefully this can get you going full speed with unit test mixins a little faster than I could.

I have a Service that receives an event that a piece of musik has been played on one of our radio stations. First I need to retrieve the channel, determine which program played it and finally call a rest-service that returns all that we know about this particular piece of musik, and then persist this particular track played.

So the service I need to test, looks like this when stripped down to its essence:

class TrackPlayedEventService {
  def musicService

  void handleTrackPlayedEvent(TrackPlayedEvent event) {
    def channel = Channel.findByName(event.channelName)
    def program = Program.findByChannelAndStartTimeLessThanOrEqualsAndEndTimeGreaterThanOrEquals(
        channel, event.startTime, event.endTime)
    def musikInfo = musicService.getTrackInfo(event.trackId)
    def trackPlayed = new TrackPlayed(trackId: event.trackId, program: program, 
        salesArtists: musikInfo.salesArtists, trackTitle: musikInfo.title)

Now in the above example, I need to have mock versions of Channel and Program as well as the resulting object of type TrackPlayed with basic GORM functionality, and to stub the musicService.getTrackInfo(trackId) method. Therefore, the Mock annotation is perfect for Channel, Program, and TrackPlayed, but for the MusikService I need to use the mockFor() method, as I need some real data returned packaged in a MusikInfo object.

@Mock([Channel, Program, TrackPlayed])
class TrackPlayedEventServiceTests {
  def eventObject
  void setup() {
    eventObject = new TrackPlayedEvent(channelName: 'P3', trackId: '1234567-1-1', startTime:
        Date.parse('yyyy-MM-dd HH:mm:ss', '2012-03-23 11:23:08'), 
        endTime: Date.parse('yyyy-MM-dd HH:mm:ss', '2012-03-23 11:27:46'))
    // Use the Channel and Program mocks created by @Mock annotation to create a channel and program
    def myChannel = new Channel(name: 'P3') false)
    new Program(channel: myChannel, startTime: Date.parse('yyyy-MM-dd HH:mm:ss', '2012-03-23 11:00:00'),
        endTime: Date.parse('yyyy-MM-dd HH:mm:ss', '2012-03-23 13:00:00')).save(validate: false)

  void testHandleTrackPlayedEvent() {
    // create mockFor service and stub the method that is to be intercepted
    def mockService = mockFor(MusicService)
    // NOTE: if the method you're mocking has zero arguments remember to start your closure with {->
    // else it will complain because of the implicit it argument to a closure
    mockService.demand.getTrackInfo {trackId ->
      return getMusikInfoObject()
    service.musicService = mockService.createMock()

    // Using the TrackPlayed mock - find (hopefully) the TrackPlayed persisted by the service method under test
    def trackPlayed = TrackPlayed.findByTrackId('1234567-1-1')
    assert trackPlayed 
    assert trackPlayed.title == 'My Song Title'

  MusikInfo getMusikInfoObject()
    return new MusikInfo(trackId: '1234567-1-1', title: 'My Song Title', salesArtists: ['Artist one', 'Artist two'])

Hopefully this has been a help to you, which means that I am not alone in taking my time to fully understand the available documentation. But in case it is only me that is slow on the uptake, I’ll take comfort in the saying that ignorance is bliss.

Using Grails with Oracle AQ as Jms provider

In a quest to modernize a legacy system, we have decided that we want to try to move the new codebase to Grails.

In essence what we need the new system to do under the hood is to receive messages on several Oracle AQ queues, persist some legacy objects in the same schema as the AQ tables and finally persist our new domain model objects in a MongoDB.

I ended up making a sample application that combines a Grails application with a modified version of the routing-jms plugin and the MongoDB GORM plugin.

My first challenge was to extend the routing-jms plugin with an oracleQueue component. I forked the routing-jms plugin on GitHub (my forked version is available at here)

Now the reason I haven’t made a pull-request back to the upstream project is an unlucky dependency on Oracles’s aqapi.jar which is not publically available via Maven (as far as I can determine).

First, I added the oracleQueue component in RoutingJmsGrailsPlugin.groovy:

Could not embed GitHub Gist 1992628: API rate limit exceeded for (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

I then needed to add the aqapi.jar dependency to the BuildConfig.groovy file:

repositories {
    // All the original repositories here ...

    // Replace with the maven repository where aqapi.jar is uploaded and uncomment!
    mavenRepo "http://artifactory:8081/artifactory/repo"

dependencies {
    // All the original dependencies here ...


To distribute the changes to the plugin, I ran grails package-plugin, and then I manually uploaded the resulting zip file to our Artifactory repository.

When I created the sample grails app, I added the following line in BuildConfig.groovy under repositories:

grails.project.repos.localReleases.url =  "http://artifactory:8081/artifactory/repo"

and then I ran grails install-plugin routing-jms --repository=localReleases so that it retrieved the plugin from our Artifactory repository.

In the created application there is still a couple configuration issues. One needs an Oracle driver jar – again one is not available through a public maven repository, so you can either drop a copy of the jar into the apps lib folder or manually configure a mavenRepo that contains a copy in BuildConfig.groovy and add a dependency instead.

The following dependencies are needed for creating your Camel route, using Jaxb, and the MongoDB plugin respectively:

runtime 'org.apache.camel:camel-jms:2.9.0'
runtime 'org.apache.camel:camel-jaxb:2.9.0'
runtime 'org.mongodb:mongo-java-driver:2.7.1'

In the Config.groovy file you need to remember to wire in the values for the following values for each environment: = "jdbc:oracle:thin:@{database-host}:{port}:{database.instance}" = "{username}" = "{password}"

It is also a pre-requisite that an Oracle AQ queue table and queue are defined and started in the Oracle schema. I have created a queue table and queue called CAMEL_TEST in our database. Our queue is defined with 2 redelivery attempts and running the sample application shows the transactional part working fine – attempting 2 redeliveries and then placing message on the error queue when the built in error traps are executed.

The DataSource.groovy also needs to be configured for access to the same Oracle schema

And away we go! (Sample application is available here)

  grails create-route AqMessage

Edit config method in the created Route

void configure() {
    def config = grailsApplication?.config
    DataFormat jaxb = new JaxbDataFormat("com.acme.order")

I have created two domain classes. The first one Order which uses the Hibernate plugin to persist to the Oracle schema and OrderMash which uses the MongoDB plugin to persist to a MongoDB which is also configured in the file DataSource.groovy. The way to get a domain object persisted with the Mongo plugin instead of Hibernate is to add the following to the domain class:

    static mapWith = "mongo"

I auto-generated the Order Controller and Views and modified the save() action to call a method on my PersistAqMessageService which basically places an xml string on the oracle Aq Queue via the injected method sendMessage:

The Service is straight forward – I have a constraint on the Order object amount(range:1..10), so it will throw an exception if out of range. Likewise, if the name is set to “FAILME” I create an OrderMash object which violates a not nullable constraint on that object.

class PersistAqMessageService {
    static transactional = true

    def persistAqMessage(PurchaseOrder purchaseOrder) {
        def myOrder = new Order(name:, price: purchaseOrder.price, amount: purchaseOrder.amount)
        if (! true)) {
            throw new RuntimeException("Yada-yada")
        } else {
   "Order object saved!"

        def orderMash
        if ("FAILME")) {
            orderMash = new OrderMash(name:, price: myOrder.price, amount: myOrder.amount)
        } else {
            orderMash = new OrderMash(pieceId:, name:, price: myOrder.price, amount: myOrder.amount)
        if (! true)) {
            throw new RuntimeException("Roll-me back back")
        } else {
   "OrderMash object persisted to Mongo"

    def putMessageOnQueue(Order newOrder) {
        sendMessage('oracleQueue:queue:CAMEL_TEST?jmsMessageType=Text', "<purchaseOrder name=\"${}\" price=\"${newOrder.price}\" amount=\"${newOrder.amount}\" />")

Et voila – run the application and create Orders via the Order form and check that an Order object is persisted in the Oracle schema and an OrderMash object is persisted in the orderMash Collection in database foo in your MongoDB.