Ode to MockFor(March): Part 2 - mockDomain


I know March has long passed. My intentions to do this series during the month of March feel grossly short due to time constrains and a little bit of laziness. In Part 1 we started our discussion of the Testing Plugin and how it helps the Grails developer test the constraints on their domain classes. This time around we are going to look at how the Testing Plugin helps you write tests that use all those methods that are injected into your Domain Class at runtime.

Why use mockDomain()

The mockDomain() method is typically used when you are testing an action on a controller or a method on a service. In most of these scenarios your action or method might be fetching a domain object from the database, doing something with it, and then calling validate() or save() on it. One approach would be to write an integration test for this. Integration tests take care of wiring up all the injected methods for our domains so that we can successfully test against them. However they are sloooowww. mockDomain() gives us most of the injected methods that we need as well as a pretty cool way to mock out a database call.

Injected methods mockDomain() gives us

  • All of your dynamic finders (findBy* and findAllBy* )
  • get
  • getAll
  • exists
  • count
  • list
  • create
  • save
  • validate
  • delete
  • discard
  • addTo*
  • removeFrom*

Injected methods that aren’t included:

  • countBy
  • createCriteria
  • executeQuery
  • executeUpdate
  • find
  • findAll
  • findAllWhere
  • findWhere
  • ident
  • listOrderBy
  • merge
  • withCriteria
  • withTransaction

Note: don’t fret if you need to test against any of these, the next post will cover the ever powerful mockFor() method.

Using mockDomain()

Here is an example of how to use the mockDomain:

Lets say we have PersonService, and we want to test the updateFirstName method that uses a Person domain.

class PersonService{

    def updateFirstName(id, name){
        def person = Person.get(param.id)
        person.firstName = name
        person.save()
        person
    }
}

We are simply, fetching the Person object from the database, updating the firstName attribute, then saving it back to the database, and then return the updated person object back to the caller.

Here is how we would write the test for this:

class PersonServiceTest extends GrailsUnitTestCase{ //1

    def service

    def setUp(){
        super.setUp() //2
        service = new PersonService() //3
    }

    def testUpdateFirstName(){
        def testPerson = new Person(id:1, fistName:'Bob')
        mockDomain(Person, [testPerson]) //4

        def result = service.updateFirstName(1, "James") //5

        assertNotNull 'should not be null', result
        assertEquals 'James', result.firstName //6
    }
}

So here is what’s going on: 1. Extend GrailsUnitTestCase: GrailsUnitTestCase extends GroovyTestCase 2. Call the parent classes setUp() method. IMPORTANT: You must do this to get all the testing goodness to work. 3. Instantiating our service class. 4. Mocking out our Person domain. We are also passing in a list of test objects that our mock domain can ‘query’ against. When our Service calls the get() method on the mocked out Person object it will look at this list for an id that matches and use it. This list will also be queried against for all of the dynamic finders and other database centric methods that are provided on our mocked out domain. The mocked out save() method will return true as long as the domain object pass validation against its constraints. 5. Execute the method under test passing the id of the object we want to get and the new first name. 6. Assert that we have successfully updated our Person with a new first name.

One other notable point: The second parameter that takes a list, of the mockDomain() method is optional. If you do not need to mock out a database “call”, then you don’t need to pass this at all.

So that pretty much it for mockDomian(). It gives you a simple but powerful way to test your controllers and services with out incurring the expense and time of integration tests.

Next up: The Swiss Army Knife of the Testing Plugin - mockFor()

,

  1. #1 by Sharad Jain - June 19th, 2009 at 08:19

    Nice Writeup. Thanks.

  2. #2 by Flo - September 8th, 2009 at 08:20

    Hi Zan!

    Nice blog post, helped me a lot thanks! Just FYI: countBy* support is injected using mockDomain since grails 1.2-M3

    kind regards, flo

    • #3 by Zan Thrash - September 8th, 2009 at 08:57

      @Flo Thanks for the heads up. I’ve been meaning to look into all the 1.2 goodness, just need to find the time. Also thanks for the Twitter follow. ~ZKT

  3. #4 by Muhammad Imamuddin - April 12th, 2010 at 04:15

    Nice Post…. very helpful … thanks

  4. #5 by Hamlet D’Arcy - August 17th, 2011 at 01:09

    cool post bro.

    But where is Part 3 ?!? I need part 3.

    Please show me the codes.

(will not be published)
  1. No trackbacks yet.