Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails Testing with Spock - Which Mocking Framework Select?

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

like image 948
kuceram Avatar asked Jul 24 '13 08:07

kuceram


People also ask

Which of the given options are mock frameworks?

Explanation: EasyMock, jMock, Mockito, Unitils Mock, PowerMock and JMockit are a various mocking framework.

How do you mock a method in Spock?

In Spock, a Mock may behave the same as a Stub. So we can say to mocked objects that, for a given method call, it should return the given data. So generally, this line says: itemProvider. getItems will be called once with ['item-'id'] argument and return given array.

How is a mocking framework used for verification?

Mocking is a process that allows you to create a mock object that can be used to simulate the behavior of a real object. You can use the mock object to verify that the real object was called with the expected parameters, and to verify that the real object was not called with unexpected parameters.

Does Spock use JUnit?

Both Groovy and Java build and run on the JVM. A large enterprise build can run both JUnit and Spock tests in the same time. Spock uses the JUnit runner infrastructure and therefore is compatible with all existing Java infrastructure. For example, code coverage with Spock is possible in the same way as JUnit.


1 Answers

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.

like image 88
dmahapatro Avatar answered Oct 21 '22 10:10

dmahapatro