I was adding out of container integration test support to an existing project and noticed that application was using threadlocals in controller to get logged in user info. In fact, an application filter authenticates/identifies the user and put it in threadlocal for the rest of the application to use. It was good first step but definitely has limitations from unit testing perspective.
Questions popped in mind were:
How to write unit tests and mock up threadlocals
can we use spring request scope beans to store user info as we can use spring dependency injections nicely
Since application filter we had was operating outside the scope of spring dispatcher servlet, how to get spring request scoped bean and store user info from application filter. [ For the curious, We are not using spring security ]
Finally, I took following steps:
Step1 - Convert ThreadLocal code to Service
Step2 - Declare the bean as request scope
Step3 - Register the RequestContextListener
In case of out of container request scope bean access, register the RequestContextListener.
We would run into below exception, if we don’t add requestContextListener:
Caused by: 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.
Step4 - Initialize your Service
Initialize the threadLocal as per your business logic. Get the access to bean via WebApplicationContextUtils.
Step5 - Inject request scope bean via constructor injection
After this we can easily mock UserInfoService in our unit tests and can inject it as a service in other service classes.