Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails 2.0 Unit-Testing Filters: service injection and dependsOn

Currently upgrading a grails 1.3.7 app to 2.1.0 and have a set of filters I'd like to test. Seeing as the grails documentation for testing filters suggests that Unit Testing for filters is now supported (/is recommended? its mentioned in the functional portion but not finding examples), I'm attempting to convert some existing integration tests for the filter into unit tests.

However, I'm struggling to properly 'mock away' a filter this filter dependsOn / at the very least properly implement a mock for some services that are being injected the filters.

package com.example

import ... // excluded for brevity


class MyFilters {

    GrailsApplication grailsApplication
    SomeService someService

    def dependsOn = [MyOtherFilters]


    def filters = {
        all(controller: 'controllerToExclude', invert: true) {
            before = {
                if (grailsApplication.config.someConfigProperty) {
                    def someProperty = request.getAttribute('MY_ATTRIBUTE')

                    if (someProperty = someService.someMethod()) {
                        redirect(url: someService.getNewUrl(session))
                        return false
                    }
                }
                return true
            }
        }
    }
}

And the other filter:

package com.example

class MyOtherFilters {   

    SomeOtherService someOtherService

    def filters = {
        all(controller: '*', action: '*') {
            before = {
                def foo

                if (params[MY_ATTRIBUTE]) {
                    foo = params[MY_ATTRIBUTE]
                    someOtherService.setMyAttribute(sitePreference, request) 
                }

                if (!foo) {
                    foo = someOtherService.getMyAttribute(request)
                }

                if (foo) {
                    request.setAttribute('MY_ATTRIBUTE', foo)
                }    

                return true
            }
        }
    }
}

This is a really skeleton simplified version of the two filters I'm working with (if anyone's curious, they read a mobile vs desktop preference and then filter based on that preference).

So the test I'm writing looks roughly like this:

package com.example

import grails.test.mixin.TestFor // ... etc more imports here

@TestFor(SomeController)
@Mock(MyFilters) // TODO what goes here???
class MyFiltersTests {

    static final IPAD_USER_AGENT = 'Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X; en-us) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3'
    static final NON_MOBILE_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.12011-10-16 20:23:00'


    void testFilterRedirects() {
        grailsApplication.config.someConfigProperty = true
        // actual filter logic acts on this user-agent through some service calls, would like to mock it out though    
        request.addHeader("user-agent", IPAD_USER_AGENT) 
        def result

        withFilters(action: "index") {
            result = controller.index()
        }

        //assertSomething on result perhaps
        assertEquals "myExpectedRedirectUrl", response.redirectedUrl
    }
}

As this code stands, it doesn't even execute the MyFilters code. I've tried adding the dependent filters to the mocking ala:

@Mock([MyFilters, MyOtherFilters]) 

But then I run into problems with the SomeOtherService methods not being defined, and have not found a way to mock those methods out properly (how do I set service mocks on a filter? on a controller or service you can def myMock = mockFor(SomeOtherService) and then do controller.someOtherService = myMock.createMock() or something of the sort, but I can't find a way to set the service for the filter with this withFilters block the documentation is suggesting to use.

Ideally, I'd be mocking out anything to do with someService and MyOtherFilters, and just writing my test on this filter, but not sure what's possible w/ testing filters.

Any insight would be greatly appreciated, thanks very much if you made it this far!

like image 422
Will Buck Avatar asked Mar 06 '13 01:03

Will Buck


1 Answers

Have the same issue. There is a bug raised in Grails Jira http://jira.grails.org/browse/GRAILS-8976

I found workaround in http://delvingintodev.carrclan.us/2012/12/testing-grails-filters-that-use-services.html 'Testing Grails Filters that use Services '

You basically have to use service in filter as follows

package xxx.me

class MyFilters {
    def filters = {
        all(controller:'*', action:'*') {
            before = {
                applicationContext.getBean(MyService).doSomethingClever()
            }
        }
    }
}

In this case you will be able to mock it in unit tests

package xxx.me

@TestMixin(GrailsUnitTestMixin)
@Mock(MyFilters)
class MyFiltersTests {

    @Test
    public void testFilter(){
        defineBeans {
            myService(StubbedMyService)
        }
        SimpleController controller = mockController(SimpleController);

        withFilters(controller:"simple" , action:"index"){
            controller.index()    
        }
    }
}

class StubbedMyService extends MyService {
    def doSomethingClever(){
    }
}
like image 189
Ivar Avatar answered Sep 23 '22 02:09

Ivar