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 service
s 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!
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(){
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With