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.

Combining mockDomain() and mockFor() in Grails

As we’ve mentioned before, anything you can do to make automated testing easier in your Grails project will help you achieve one of the primary goals of the platform – high productivity.

Since you’ve chosen the Grails platform, you’re likely making good use of its features such as GORM, plugins, convention based spring wiring and Config.groovy/ConfigurationHolder. These all help you get to the business of writing your code without having to deal with plumbing all the time. Unfortunately the byproduct is that these all can make automated testing quite painful. Many times you end up going with integration tests simply because these give you access to the free plumbing even though you really just need to write unit tests. I won’t bother here debating and comparing unit vs. integration tests since this has been discussed many times before. We’ll just assume we want to write unit tests.

Grails (assuming 1.3.7) does provide the mockDomain(class, [instances]) which gives you an available “database” of objects in memory as provided to the mockDomain method without the need for a running container – perfect for unit tests. Unfortunately, as you start writing unit tests and encountering some issues, you come across this little gem in the documentation

… does not support the mocking of criteria or HQL queries

. That’s too bad really. You’d think they could easily support it, even if they just used an actual in memory database. Anyway, the documentation then adds

If you use either of those, simply mock the corresponding methods manually (for example with mockFor() ) or use an integration test with real data.

Sure, we could write an integration test, but we really don’t want to and shouldn’t have to. What about that mockFor() approach? Well you’re likely here because nobody has documented actually how to do so. We’re here to help. Here we’ll cover off combining mockDomain() with mockFor() for criteria in this post. In a future post, we’ll take a look at HQL queries.

It turns out to be not too bad. The use of closures leaves a little to be desired, but that’s not specific to this problem as it’s common to all mockFor(Domain).demand usage. Our example will assume you are using withCriteria to do something like find a range of data. We’ll also show you how you can provide other free behaviour via mockFor() – such as provided by a plugin.

We’ll have a domain class Order looking for orders placed within a specific date range and then provide mock behaviour for toDTO(dtoClass).

def order1 = new Order(orderId : 1, date : new Date(), amount : 19.99)
def order2 = new Order(orderId : 2, date : new Date(), amount : 39.99)
def order3 = new Order(orderId : 3, date : new Date(), amount : 49.99)
def order4 = new Order(orderId : 4, date : new Date(), amount : 99.99)
def orders = [order1, order2, order3, order4]
def mocker = mockFor(Order, true)
mocker.demand.toDTO(1..4) { clazz ->
    return new OrderDTO(orderId: delegate.orderId, date: delegate.date, amount: delegate.amount)
}
mocker.demand.static.withCriteria(1) {criteriaClosure ->
    def found = []
    orders.each { order ->
        if (criteriaClosure.from >= order.date && criteriaClosure <= order.date) {
            found << order
        }
    }
    return found
}
mockDomain(Order, [order1, order2, order3, order4])

Let's review what we've done. We create some test order instances for use both from our "database" and our mockFor / withCriteria logic. mockFor() gives us our handle to the mock that we can now set our expectations against since we're not really worried about testing against the mock and verifying its usage, we just need it to substitute for the database. toDTO is the free method you get with the DTO plugin. Use the mocker.demand as you would any grails mock. Then we substitute for the withCriteria code. Just make sure you use demand.static for withCriteria. We apply the logic against our collection of test instances (could just as easily have used the mocked instances available via mockDomain by doing Order.list().each) and now have a valid functioning "database" that supports criteria in unit tests.

Of course this doesn't actually test that your withCriteria is implemented correctly. The focus here was to establish an expected set of data to test against. You would have to write integration tests to actually test these types of methods on your model classes.

Testing in Grails – Common base class for Unit/Integration/Functional Tests

Groovy and even more so, Grails, demands automated testing. In fact, extensive coverage is a must to have confidence that we are not regressing or introducing runtime resolution issues with a single errant keystroke. Grails expects you to write tests and each grails project has the familiar test/unit, test/integration and test/functional source folders. Of course, we want to make it as easy as possible to write our tests. You already use a common base class for your grails tests, GrailsUnitTestCase. And it is a well-established practice in environments using testing frameworks such as jUnit to extend this approach to your own needs.

For example, it’s nice to be able to verify failure cases as we discussed in our last post. Perhaps you’re using a helper similar to the one previously described (shown below) in a base unit test class and want to extend its use to integration tests.

def expectThrown(Class expectedThrowable = Throwable, Closure closure) {
    try {
        closure()
    } catch(Throwable t) {
        if (!expectedThrowable.isInstance(t)) {
            throw t
        }
        return t
    }
    throw new AssertionError("Expected Throwable $expectedThrowable not thrown")
}

Well, if you have the base class in your test/unit source folder, it’s not available to test/integration and test/functional. You can place the base class src/groovy, but then this becomes a production class and is included in your .war file.

The current “solution” actually does start there. Place your base class in src/groovy. Then we want to add an exclusion in BuildConfig.groovy to ensure that this class – and any others you want excluded – are not packaged in the war.

BuildConfig.groovy

grails.war.resources = { stagingDir ->
    delete(file:"${stagingDir}/WEB-INF/classes/com/carfey/test/CarfeyGrailsTestCase.class")
    delete(dir:"${stagingDir}/WEB-INF/classes/com/carfey/test")
}

Tested against Grails 1.3.7.

Testing Failure Cases in jUnit in Java & Groovy

Unit testing expected failure cases is just as important as testing expected positive behaviour. In fact, you could argue that ensuring all failures are happening as expected is more important since it’s one of your best defenses against bad data. If you search for examples of how to test for failures (using old style jUnit 3), you’ll likely come across something like this.

public void testException() { 
    try { 
         Object o = getList().get(0)
         fail("Should raise an ArrayIndexOutOfBoundsException"); 
    } catch (ArrayIndexOutOfBoundsException e) { 
    } 
}

or perhaps

public void testException() { 
    try { 
         Object o = getList().get(0)
    } catch (ArrayIndexOutOfBoundsException e) {
        return;
    } 
    fail("Should raise an ArrayIndexOutOfBoundsException"); 
}

While both of these approaches are ok, they aren’t quite as precise as a good unit test could be. First, you want to be very specific with your verification. Let’s say down the road someone starts throwing an ArrayIndexExceedsSizeException that is a child of ArrayIndexOutOfBoundsException. Your test case will continue to pass. This isn’t ideal since you’ll want to update your test cases to verify all variations of runtime behaviour. And also, neither of these approaches gives you a decent way of making additional assertions against the exception (checking for messages, error codes, etc.)

This takes a bit more code, but the following will always be accurate and will start failing when these types of changes happen and gives you a clear approach for additional assertions.

public void testException() { 
    ArrayIndexOutOfBoundsException actual = null;
    try { 
         Object o = getList().get(0)
    } catch (ArrayIndexOutOfBoundsException e) {
        actual = e;
    } 
    assertExceptionThrown(ArrayIndexOutOfBoundsException.class, actual);    
    assertEquals(actual....
}

protected static void assertExceptionThrown(Class expected, Exception actual) {
	if (actual == null || !actual.getClass().equals(expected)) {
		fail("Exception thrown not of type " + expected.getName() + " but was " + (actual == null ? "null" : actual.getClass().getName()));
	}
}

For groovy tests, you can use the above, or you can use the beauty of closures.


void testException() {
    def ex = expectThrown(ArrayIndexOutOfBoundsException) {
        Object o = getList().get(0)
    }
    assert ex.message....
}

def expectThrown(Class expectedThrowable = Throwable, Closure closure) {
    try {
        closure()
    } catch(Throwable t) {
        if (!expectedThrowable.isInstance(t)) {
            throw t
        }
        return t
    }
    throw new AssertionError("Expected Throwable $expectedThrowable not thrown")
}

You can put these and other exception assertion helpers in a base class that extends your jUnit test class (TestCase or GroovyTestCase). In our next post, we’ll cover how to get around some Grails issues sharing test base classes amongst unit, integration and functional tests.

Groovy for Scheduling

While we’ve already written a post on our scripting support in Obsidian, this post will focus specifically on our Groovy support, what we use it for and what it makes possible for you.

Given that Groovy is built for the JVM and almost any java code will work as is in a groovy script/class, supporting Groovy in Obsidian makes all sorts of things not only possible, but downright simple. Internally, Obsidian uses Groovy scripts to support a few different dynamic/configurable jobs. First, we have SpringBeanJob. This job is intended to serve one of two purposes. First, maybe you’re already using TimerTask in conjunction with Spring for scheduling. But you’re switched over to Obsidian for a more feature rich scheduling experience. You want to get up and and running quickly? Use SpringBeanJob and get your job running on Obsidian without a build/deployment cycle.

All you need to do is configure this job with the code needed to get an instance of your bean. And you indicate the name of the method(s) to call. Optionally, you can indicate the classes you need to import if you don’t wish to fully qualify your code. Here’s a sample of what the Groovy script will look like.

import com.carfey.myproject.TimerTaskBean
import com.carfey.myproject.SpringContext

def springBeanObject = SpringContext.get(TimerTaskBean.class)

springBeanObject.fireFirstMethod() //maybe run() used to call two separate methods
springBeanObject.fireSecondMethod()

That’s basically how it will work using our standard GroovyJob. Now, let’s consider the second possible use. Maybe you have a wired bean that you want to run on a schedule. To use it with TimerTask or even Quartz/Spring integration, you’d have to go through a build/deploy cycle, if only to modify Spring config. Now look back at the Groovy script above. With Obsidian, it’s the exact same approach as in our last case, with the beauty of no build or deploy. Use SpringBeanJob, get your bean handle, invoke your method(s).

We also use GroovyJob internally to provide a ReflectiveJob which is similar in nature to our SpringBeanJob, but provides support for arguments in Constructor and method calls.

But really, while our free utility jobs are easy to use and can serve some useful purposes, there’s no need to restrict yourself to these specific cases. We have created the GroovyJob so you can do pretty much anything you’d like.

Think about all the cases where dynamic access to an environment might prove useful. Maybe you need to get some data from the database to assist in troubleshooting, or you’d like to throw a quick job out to deal with some emergency condition, or just keep a failing job running by working around a failure condition. Or maybe during a testing cycle, a job is failing and you can’t figure out why. Imagine being able to take the job code, add in some extra logging lines, extract some contextual data from the db, disable the existing job and schedule a GroovyJob with your new script code. And as you get feedback, adjust and rerun. You’re probably starting to see how powerful the GroovyJob can be.

For security purposes, we don’t expose any of our script jobs in our live online demo, but download Obsidian and try them out.

The scripting jobs were available in our initial Obsidian release and these new freely provided utility jobs will be released in the upcoming release, Obsidian 1.3. Keep watching this space for a release announcement.