Grails Testing with Spock – Which Mocking Framework Select

grailsgrails-2.0spocktesting

I have more general question. Which framework or implementation I should use for mocking in Grails 2.x when using Spock?

I know tons of mocking style: leverage Groovy metaClass, Grails mockFor(), Groovy Mock(), Groovy closure style, etc. Each of them has its own advantages and disadvantages. But what I don't understand is that some mocking style works in certain occasions which I cannot determine (i.e. mockFor() works for certain implementation and not for the others).

Currently I have two similar implementation of service method mocking.

This one works:

@TestFor(MyController)
@Mock([MyDevice])
class MyControllerSpec extends ControllerSpec {

void "test st."() {
      def myService = mockFor(MyService)
      myService.demand.myMethod() { def st ->
         return "test"
      }
      controller.myService = myService.createMock()
}
}

However, this implementation doesn't work:

@TestFor(MyController)
@Mock([MyDevice])
class MyControllerSpec extends ControllerSpec {

void "test st."() {
      def yourService = mockFor(YourService)
      yourService.demand.yourMethod() { def st ->
         return "test"
      }
      controller.yourService = yourService.createMock()
}
}

The service implementation and calling from controller is quite similar. So what is the best practice of mocking in Grails? Or is there any GOOD mocking framework for Grails which would save my time figuring out how to mock?

Thanks for any advice! 🙂

Mateo

Best Answer

When you are using spock framework for testing, then try to leverage the options and styles provided by the framework itself.

Spock framework helps in achieving a BDD [Behavioral Design Development]. By behavior I meant, you can tightly couple the business acceptance scenario to the development cycle.

I tried to get your test case written in Spock as it can be re-written as:

@TestFor(MyController)
class MyControllerSpec extends ControllerSpec {

    void "test service method in called once and only once"(){
        //Defines the behavior of setup
        setup: "Only one invocation of service method" 
            def myService = Mock(MyService){
                //Make sure serviceMethod is called only once from the controller
                //Beauty of Spock is that you can test the cardinality of
                //method invocations.  
                1 * serviceMethod() >> "Hello"
            }
            controller.myService = myService

            //The above process can be followed 
            //for stubbing/mocking 'YourService' and 
            //then injecting it to controller like
            //controller.yourService = yourService

        //Defines the behavior of action
        when: "controller action is called" 
            controller.myAction()

        //Defines the behavior of expected results
        then: "Expect the stubbed service method output" 
            controller.response.contentAsString == "Hello"
    }
}

//Controller
def myAction() {
    render myService.serviceMethod()
}

If you see above, you define the behavior in each step. From an enterprise perspective, those behavior will be driven by BA or the stakeholders. By this way, you comply to ATDD/BDD(Acceptance Test Driven Dev/Behavior Test Driven Dev) and eventually a TDD(Test Driven Dev) for your project.

For more details on how to use spock framework effectively, visit spock framework docs.

Related Topic