Alrighty, I’m starting a little series this month exploring Grails unit tests. Some of you guys are already further along this road than me, so if you have smarter ways of doing things, don’t hesitate to add comments. My Grails testing kungfu is pretty white belt.

We’re starting the journey with taglibs, since they typically front pretty minimal logic, and often don’t need too much mocking. Probably the only things you have to mock out is the “out” attribute, since that’s where your taglib is dumping data. When using grails integration tests, you get the mocked “out” for free, but for now we’re on our own in Unit Testing land.

So what’s the plan? I’m getting my ideas from the grails.org tests which Graeme has put together to give us some good examples of how to mock things out.

So here’s our little taglib routine that’s under test…

    def dateFromNow = { attrs ->

        def date = attrs.date

        out << getNiceDate(date)   // eg "1 minute ago" or "1 hour ago" or "right now"

    }

I use this guy on the groovyblogs home page where you want a nice way of expressing how recent a post was (“right now”, 1 hour ago”, etc). We’ll need to deal with that “out” param through some ExpandoMetaClass magic. I’m doing this mocking process in the setUp() routing of my test. I’m just using a standard StringWriter to represent the out stream. When I’m done, I remove the mocked out lest it live on to side-effect future tests.

    // mocked "out" for taglib
    StringWriter out

    /** Setup metaclass fixtures for mocking. */
    void setUp() {
        out = new StringWriter()
        EntriesTagLib.metaClass.out = out
    }

    /** Remove metaclass fixtures for mocking. */
    void tearDown() {
        def remove = GroovySystem.metaClassRegistry.&removeMetaClass
        remove EntriesTagLib
    }

So now we’ve mocked out the “out”, it’s time to run some real tests:

    void testDateFromNow() {

        EntriesTagLib btl = new EntriesTagLib()

        Calendar cal = Calendar.getInstance()

        btl.dateFromNow(date: cal.time)

        assertEquals "Right now", out.toString()

        // reset "out" buffer
        out.getBuffer().setLength(0)

        cal.add(Calendar.HOUR, -1)
        btl.dateFromNow(date: cal.time)

        assertEquals "1 hour ago", out.toString()

    }

So my selection of a StringWriter meant I had to do some reseting of the buffer between runs, which is not so clean (and totally not threadsafe), but I am up and running - and Gravl now has its first Unit test.

That was pretty painless, runs in under a second, and we’re off and testing… Have a look at the final class here.

Now on to Controllers and Services…