Using mockFor() and HQL

In a previous post, we discussed how to actually go about combining mockFor() and mockDomain() when it comes to unit test support for .withCriteria. If your code uses the Gorm.createCriteria(), you’ll likely want to switch to .withCriteria to make it unit testable. We promised to cover using HQL as well so let’s do that now. Again, we’re assuming Grails 1.3.7.

The approach is unchanged from mocking criteria calls. We still need to use mockFor() to mock the static method usage. In our example, we’re using HQL because it’s easier to read and maintain than the equivalent criteria structure. Whatever your rationale, you should be able to follow along.

def defaultJobState = JobState.findAll(
    "from job_state where job_id = :jobId and default_state = :defaultState", 
    [jobId: jobId, defaultState : defaultState])
def orderedJobStates = JobState.findAll(
    "from job_state where job_id = :jobId and end_date >= :endDate order by effective_date", 
    [jobId :jobId, endDate : endDate])
... code for processing returned data

To make things interesting, our example shows two different HQL uses and named parameters. We’ll show how to differentiate between multiple uses and this can be applied to the criteria scenario as well. When we adopt our previous approach to HQL usage, we get the following unit test code.

    def testJobs = [defaultJobState, oldJobState, currentJobState]
    mockFor(JobState, testJobs)
    def mock = mockFor(JobState)
    mock.demand.static.findAll(1..5) { hqlString, params ->
        if (hqlString.contains("default_state")) {
            testJobs.findAll{ testJob ->
                testJob.defaultState == params.defaultState
	} else if (hqlString.contains("end_date")) {
            testJobs.findAll{ testJob ->
                testJob.endDate >= params.endDate
        } else {

As you can see, we’re effectively implementing the equivalent to the HQL. We’re making some assumptions about our expected HQL usage – that we are only testing for two usages and that no other usages will be called or can default to no data and that no other uses, if called, will give false matches on our string checks. In your case, you would probably want to make a constant out of the HQL strings and then do exact matches against those values in your test. You might also want to enhance your use to throw an exception in your else block to protect against unexpected uses. Use your testing experience to make sure yours tests are correct and adequate.