Sunday, April 25, 2010

How to stub message method in a controller

Hello Gang!  Based on the feedback from all you guys, here's a post about how easily can we stub the message method while writing controller Unit tests.

Lets take the example of my good old friend, YES the PersonController

Requirement:

After saving a person user should be redirected to show view, with a flash message indicating user was saved successfully.

Controller Code:
We have seen similar code in the past lets look at it again

We are not interested in code showing the action required if errors are returned while saving a person (As we had already covered that here)

Only different between the earlier code and this one is the flash.message and the use of message method.

How will we test it - How do they do it!:

In the grails environment, a method called message is dynamically added to the instance of PersonController, but how do we write a unit test for this?

All our controller test cases have been extending ControllerUnitTestCase which adds a lot of utility methods and fields to the controller instance.  But unfortunately it does not stub out the message method.  Hence, to test the above code we will have to stub out the message method manually. How? remember metaClass technique from my earlier post we will apply it here as well.

  1. Stub out the save method (on the person instance ) to return true, using the metaClass of Person
  2. Add a dummy message method on the controller instance, again using the metaClass of controller
  3. Assert that flash.message was correctly set by the PersonController 
  4. Remember to remove the metaClass of Person using which we stubbed the save method using the GroovySystem class.  (For explanation on why is this necessary see this post)
   
Test code looks like this:

If you notice we didn't use removeMetaClass for the controller instance. Why? because our test case extends ControllerUnitTestCase which creates a new instance of the controller class under test (in this case PersonController)before every test case is run. And hence we don't bother to use the removeMetaClass for the controller instance.

That's all folks!  As we can see metaClass is a real boon for unit testing

As uaual feedback, comments and complaints are welcome as always!
Have some Fun!