Grails3 Controller Integration Test Error: No Thread Binding Request Found

With just a simple next controller action: spock integration-test. Here is my test.

@Integration @Rollback class TestControllerSpec extends Specification { def setup() { } def cleanup() { } void "test something"() { setup: def c = new TestController() c.index() expect: c.response.contentType !=null } } 

getting the next exception

 java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) at grails.web.api.WebAttributes$Trait$Helper.currentRequestAttributes(WebAttributes.groovy:45) at grails.web.api.ServletAttributes$Trait$Helper.getRequest(ServletAttributes.groovy:42) 
+5
source share
2 answers

I do this and it works fine:

Add field:

 @Autowired WebApplicationContext ctx 

In setup() : GrailsWebMockUtil.bindMockWebRequest(ctx)

In cleanup() : RequestContextHolder.resetRequestAttributes()

+9
source

Unfortunately, it may be a limitation in Grails 3 that you cannot use integration tests to test controllers.

For integration test controllers, it is recommended that you use create-functional-test to create a Geb functional test.

Source from Grails documentation

This seems to be a major change in direction from previous versions of grails. If you really need to test the controller in an integration test, you can try to do this:

NOTE. . I understand that this can be bad practice, and this goes against the Grails documentation, but sometimes you also need to test things more programmatically when unit tests are not enough and these Geb tests are not granular enough.

 @TestFor(TestController) // This will provide a mocked "controller" reference @Integration @Rollback class TestControllerSpec extends Specification { // If TestController uses any services, have them autowired into this test @Autowired SomeService someService def setupSpec() { // Now connect those services to the controller controller.someService = someService } void "test something"() { when: controller.index() then: response.contentType != null } } 

WARNING: After some additional work with this format, I found a problem. Using @TestFor will call Holders.clear() when it is completed, which means that there will be no grailsApplication object in grailsApplication . This will cause problems if you have any integration tests that run after one that uses the above approach. After multiple digging, it doesn't seem like there is a simple (or even tough) way to do this work, and maybe for some reason this is not supported in Grails 3. Note that one of the options is to mark other integration tests using @TestFor , so that the Holders class will be correctly populated. Is it a hack? Yes it! . You will need to decide whether to apply this overhead for all tests. In my case, it was just one other integration test that needed it (since it is a small application), but if it were more, I would not use this approach.

+4
source

All Articles