Grails Testing with Spock - Which Mocking Framework Select?
Asked Answered
M

1

8

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

Macgregor answered 24/7, 2013 at 8:48 Comment(3)
Have you tried Spock's mock framework? It's really clear and straightforward. The spock docs say it can work with either spock mocks or Groovy mocks, but warn not to try combine the two mock frameworks for some reason.Lucindalucine
Yes, this is actually what's going to be used when you call mockFor(); grails.plugin.spock.UnitSpec.mockFor() is called. What I found most useful is to use directly metaClass programming for mocking as well as groovy closures. The only problem with this is that metaClass could interfere with other tests when you don't clean it in the threat down section. Maybe Grails 2.3 would bring a better support as the Spock would be default for this version...Macgregor
If the answer is appropriate and meets your expectation then accept it to help others learn from your question.Priestly
P
8

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.

Priestly answered 26/7, 2013 at 2:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.