简体   繁体   中英

Grails 3: Unit Testing Interceptors: Doesn't halt in interceptor

For demo purposes I have set up a fresh grails application with these files:

class HalloController {

    def index() {
        String heading = request.getAttribute("heading")
        render "${heading}"
    }
}
class HalloInterceptor {

    boolean before() {
        request.setAttribute("heading", "halloechen") // *** set breakpoint here***
        true
    }

    boolean after() { true }

    void afterView() {
        // no-op
    }
}

When I got to http://localhost:8080/hallo "halloechen" gets printed as this was set as an request attribute in the interceptors before() method, just like I wanted it to be. Now I want to have a unit test for the interceptor:

class HalloInterceptorSpec extends Specification implements InterceptorUnitTest<HalloInterceptor> {

    def setup() {
    }

    def cleanup() {

    }

    void "Test hallo interceptor matching"() {
        when:"A request matches the interceptor"
            withRequest(controller:"hallo")

        then:"The interceptor does match"
            interceptor.doesMatch() && request.getAttribute("heading") == "halloechen"
    }
}

This test fails as the heading attribute does not get set to the request (which is a mocked request anyway). In fact, when running the unit test it seems as the interceptor doesn't even get called. I have set a breakpoint in the before() method and when debugging the test I never get there. Which is odd because I would expect a Interceptor test to call the interceptor at least. I know I could rewrite the test as described here but my point is that the interceptor doesn't get called at all. Is that right? Another thing: calling getModel() in the test alway returns null . How do I get the model in my test?

The trick for me was calling the interceptors before() method myself:

import grails.testing.web.interceptor.InterceptorUnitTest
import spock.lang.Specification

class HalloInterceptorSpec extends Specification implements InterceptorUnitTest<HalloInterceptor> {

    def setup() {
    }

    def cleanup() {

    }

    void "Test hallo interceptor matching"() {
        when: "A request matches the interceptor"
        withRequest(controller: "hallo")
        interceptor.before()

        then: "The interceptor does match"
        interceptor.doesMatch() && request.getAttribute("heading") == "halloechen"
    }
}

If this persist with withInterceptors it's probably because of https://github.com/grails/grails-testing-support/issues/29

A workaround is by adding a fake "loading interceptors test" before the real ones:

    void "Fake test to load interceptor"() {
        // this is necessary because of this: https://github.com/grails/grails-testing-support/issues/29
        given:
            def controller = (PostController) mockController(PostController)

        when:
            withInterceptors(controller: 'post') { true }

        then:
            true
    }

You need to use the withInterceptors method instead of the withRequest - withRequest only validates matching or not - so the interceptor is never actually ran.

From the docs:

withInterceptors:

You can use the withInterceptors method to execute code within the context of interceptor execution. This is typically done to call controller actions that rely on behavior from interceptors .

https://testing.grails.org/latest/guide/index.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM