Monday, March 15, 2010

Grails Goodness: Using MetaClass with Testing

We can use the metaClass property of classes to define behavior we want to use in our tests. But if we do, the change is not only for the duration of a test method, but for the entire test run. This is because we make a change at class level and other tests that use the class will get the new added behavior. To limit our change to a test method we first use the registerMetaClass() method. Grails will remove our added behavior automatically after the test method is finished.

Let's see this with an example. We have a domain class User which uses the Searchable plugin. This plugin will add a search() and we want to use in our test case.

class User {
    static searchable = true
    String username

class UserTests extends GrailsUnitTestCase {
    void testSearch() {
        registerMetaClass User
        User.metaClass.static.search = { searchText ->
            [results: [new User(username:'mrhaki')],
             total: 1, offset: 0, scores: [1]] 
        assertEquals 'mrhaki', User.search('mrhaki').results[0].username


Phil H said...

What if I want to stub out a query that is a subroutine of another function? Using your example, let's say User has a "doSearch" which calls "search" and then does some useful processing of the results, either returning the list or throwing an error (maybe results was null).
You'd write 2 separate test cases and mock the function to return good or bad data depending on what you were testing, but how do you make the function use the mocked function as opposed to trying to use the "real" one?

Thanks for the help...

Phil H said...

Whoops-- seems that it was because I didn't make the methods static.
Now to figure out how to do this with non-static methods!

BalRog said...

Why not just use gmock? http://code.google.com/p/gmock/

Post a Comment