Monthly Archives: February 2012

Grails 2.0 mockFor() Gotcha

Update: When I was researching another Grails issue, I found out that what I encountered below looks to be fixed in Grails 2.0.1. I have yet to verify the fix, but if you also encounter this issue I urge you to try Grails 2.0.1 to see if it resolves the problem.

I am working on a Grails 2.0.x project and am quite enjoying some of the new features that are part of the current Grails release. The new test mixins that are part of Grails 2.0.x are awesome and really simplify the creation of your unit test classes. But I ran across a “gotcha” when using the test mixins.

I was writing a unit test class for a Grails controller, and was using the default template that gets created via:

grails create-controller com.asoftwareguy.example.Example

One of the helper methods exposed by the GrailsUnitTestMixin is the mockFor() method, which is a simplified way of creating a new Groovy mock. I though this to be much cleaner than needing to instantiate a new MockFor() every time I needed a mock proxy for an interface. However, I ran into an issue where the proxy instances created by the mockFor() method of the mixin are not cleaned up between test case runs. Let me give an example of what was failing.

ExampleController.groovy


package com.asoftwareguy.example

class ExampleController {

  def exampleService

  def index() {
    def something = exampleService.doSomething()
    render (view: 'index', model: [something: something])
  }
}

ExampleService.groovy

package com.asoftwareguy.example

interface ExampleService {
  List doSomething();
}

ExampleControllerTests.groovy

package com.asoftwareguy.example

@TestFor(ExampleController)
class ExampleControllerTests {

  void testDoSomething_first_time() {
    def mockService = mockFor(ExampleService) //use the mixin
    mockService.demand.doSomething() { ->
      return true
    }
    controller.exampleService = mockService.createMock()
    controller.index()
    // assertions
  }

  void testListStations_second_time() {
    def mockService = mockFor(ExampleService) //use the mixin
    mockService.demand.doSomething() { ->
      return true
    }
    controller.exampleService = mockService.createMock()
    controller.index()
    // assertions
  }
}

With the above code in place, the first test case would always pass, but the second test case would fail with the following error:

| Failure:  testListStations_second_time(com.asoftwareguy.example.ExampleControllerTests)
|  junit.framework.AssertionFailedError: No more calls to 'doSomething' expected at this point. End of demands.
at grails.test.MockClosureProxy.doBeforeCall(MockClosureProxy.java:66)
at grails.test.AbstractClosureProxy.call(AbstractClosureProxy.java:74)
at com.asoftwareguy.example.ExampleController.index(ExampleController.groovy:xx)
at com.asoftwareguy.example.ExampleControllerTests.testListStations_second_time(ExampleControllerTests.groovy:xx)
| Completed 2 unit tests, 1 failed

After some troubleshooting and debugging the issue, I have concluded that there is a bug in the version of Grails I running (2.0.0) and hopefully it is fixed in the next release. As a workaround, I have reverted to instantiating new MockFor() instances within each test case.