views:

608

answers:

1

I want to test a Grails controller which calls a service. I'd like to mock the service. The Service has a method:

JobIF JobServiceIF.getJob(int)

and JobIF has a method:

String JobIF.getTitle()

Here's my controller

def workActivities = {
   JobIF job = jobService.getJob(params.id)
   [career:job]
}

I understand that I need to mock the service and the job class (there are concrete implementations for both) but I'm struggling to get my head around the Groovy mocking object syntax. How do I mock a job and set the title to something, say "Architect" and then test the code?

So far I have:

void testWorkActivities() {
   def controller = new CareersController()
   ... // Mocking stuff I don't know how to do
   controller.params.id = 12
   def model = controller.workActivities()
   assertEquals "Architect", model["career"].getTitle()
}
+3  A: 

You basically have two choices

  1. Use the Groovy mocking classes, i.e. MockFor and StubFor
  2. Use the Grails mock classes by calling the mockFor method of GrailsUnitTestCase. The class returned by this method is an instance of GrailsMock

Personally, I have found the Groovy mock objects to a bit more reliable than the Grails mocks. On occasions, I've found that my Grails mock objects were bypassed, even though I appeared to be setting everything up correctly.

Here's an example of how to use the Groovy mocks:

void testCreateSuccess() {

    def controller = new CareersController()

    // Create a mock for the JobService implementation class
    def mockJobServiceFactory = new MockFor(JobService)

    mockJobServiceFactory.demand.getJob {def id ->
        // Return the instance of JobIF that is used when the mock is invoked
        return new Job(title: "architect")
    }

    // Set the controller to use the mock service
    controller.jobService = mockJobServiceFactory.proxyInstance()

    // Do the test
    controller.params.id = 12
    def model = controller.workActivities()
    assertEquals "Architect", model["career"].getTitle()
}

The process is basically the same when using the Grails mocks, but you call the mockFor method of the test class, instead of instantiating MockFor.

Don
Thanks. Can I ask one more question? If the JobService has a constructor argument - how do I specify that? For example JobService takes a JobDao as it's constructor arg. Thanks.
Matt
The stacktrace by the way is:Testcase: testWorkActivities took 0.344 sec Caused an ERRORCould not find which method <init>() to invoke from this list: public uk.co.cascaid.biz.job.JobObservableCachedService#<init>(uk.co.cascaid.dao.job.JobDaoIF, uk.co.cascaid.biz.common.paging.PageCollectionServiceIF) public uk.co.cascaid.biz.job.JobObservableCachedService#<init>(uk.co.cascaid.dao.job.JobDaoIF)org.codehaus.groovy.runtime.metaclass.MethodSelectionException:
Matt