0

I would like to mock a service method in an integration test for one test, however I don't know how to get a reference to the service as it's added to the controller via dependency injection. To further complicate things the service is in a webflow, but I know it's not stored in the flow as the service is not serialized.

Ideal mocking scenario:

  1. Get reference to the service

  2. Mock the method via the metaClass

  3. Main test

  4. Set the metaClass to null so it's replaced with the original

Methods like mockFor so far don't seem to effect the service.

Example of the setup: Controller:

package is.webflow.bad
import is.webflow.bad.service.FakeService

class FakeController
{
    def index = {
            redirect(action: 'fake')
        }

        def fakeFlow = {

            start {
                action {
                    flow.result = fakeService.fakeCall()
                    test()
                }
                on('test').to('study')
            }

            study {
                on('done').to('done')
            }

            done {
                System.out.println('done')
            }
        }
}

Service:

package is.webflow.bad.service

class FakeService
{
    def fakeCall()
    {
        return 'failure'
    }
}

Test:

package is.webflow.bad

import static org.junit.Assert.*
import grails.test.WebFlowTestCase
import is.webflow.bad.service.FakeService

import org.junit.*

class FakeControllerFlowIntegrationTests extends WebFlowTestCase
{
    def controller = new FakeController()

    def getFlow() { controller.fakeFlow }
    String getFlowId() { "fake" }

    @Before
    void setUp() {
        // Setup logic here
        super.setUp()
    }

    @Test
    void testBasic()
    {
        startFlow()
        assertCurrentStateEquals 'study'
        assertEquals 'failure', getFlowScope().result
    }

    @Test
    void testServiceMetaClassChange()
    {
        // want to modify the metaClass here to return success

        startFlow()
        assertCurrentStateEquals 'study'
        assertEquals 'success', getFlowScope().result
    }
}
Lifeweaver
  • 986
  • 8
  • 29
  • Would something like Mockito's [InjectMocks](http://site.mockito.org/mockito/docs/current/org/mockito/InjectMocks.html) annotation help you? – Shawn Bush Jan 12 '15 at 15:03
  • I'm not familiar with Mockito however it looks like I would still need to replace the instance of the FakeService but I don't know how to get a reference to it. – Lifeweaver Jan 12 '15 at 16:37
  • I guess I misread and didn't realize you only want to mock part of the FakeService. Unless you can use Autowired with the RunWith annotation (as described here: http://patrickgrimard.com/2011/02/17/running-unit-tests-with-the-spring-framework/) then I don't know how to answer this. – Shawn Bush Jan 12 '15 at 16:48

2 Answers2

0

You can inject the service into your Integration test using "@AutoWired" or using application context you get reference. Am i missing something?

  @Autowired
  private YourService yourservice;

or

    @Autowired
        private ApplicationContext appContext;

YourService yourService = (YourService)appContext.getBean("yourService");
Chandru
  • 964
  • 11
  • 16
  • This does get an instance of the service but seems to not get the one the webflow is using. Any change I make to the service's metaClass does not take affect. I had a method that worked by overriding the service class's metaClass but it fails when the test if ran with other tests that call that service before it http://stackoverflow.com/questions/27623737/how-to-keep-services-metaclass-from-being-overridden – Lifeweaver Dec 29 '14 at 19:47
0

Here you go:

void "test something"() {
    given: "Mocked service"
    someController.someInjectedService = [someMethod: { args ->
        // Mocked code
        return "some data"
    ] as SomeService

    when: "Controller code is tested"
    // test condition

    then: "mocked service method will be called"
    // assert
}
Shashank Agrawal
  • 25,161
  • 11
  • 89
  • 121
  • The service is added to the controller via dependency injection there is no `someController.someInjectedService` there is not even a `def someInjectedService` in the controller it's merely used like `someInjectedService.someMethod`. – Lifeweaver Dec 29 '14 at 19:51