We have a Java web application that is instantiated using Guice and the Guice Servlet extension. The application also includes Quartz jobs that are also instantiated by Guice. I want to write unit test for these jobs.
The job classes depend on other other classes from our productive code which require a Provider<HttpServletRequest>
. In the productive setup, the jobs can be successfully instantiated by Guice, and the jobs work as expected because they never call any code on their their collaborators that triggers a get
on the servlet request provider. Such a get
call would fail because the jobs are executed by some worker thread, and not as part of an HTTP request to the servlet.
Now my question is how to set up Guice in a JUnit test so that I get the same behaviour, i.e. the job classes can be instantiated, but all attempts to use any out-of-scope @RequestScoped
objects would fail.
There are two straigtforward solutions, but they don't work for me.
If I don't bind any HttpServletRequest
, I get an error when trying to instantiate the job in the test setup:
com.google.inject.CreationException: Guice creation errors:
1) No implementation for javax.servlet.http.HttpServletRequest was bound.
while locating com.google.inject.Provider<javax.servlet.http.HttpServletRequest>
If on the other hand I just bind mock instances, e.g. with
@Override
protected void configure() {
bind(HttpServletRequest.class).toInstance(mock(HttpServletRequest.class));
}
then the job can be instantiated, but I no longer get a test error in case the job makes use of the servlet request instance. So how can I create a binding so that Guice is able to instantiate providers, but any use of the providers would fail?
After a few attempts, I found out how to bind
@RequestScoped
objects in a test module:The tests never enter the request scope (i.e. there are no calls to
ServletScope.scopeRequest
), so all attempts to obtain theRequestScoped
objects in the tests would result in exactly the same error as in production:Binding an "unusable provider" isn't actually necessary - I just did it as an extra safety net. This means that this solution should also work for classes which aren't explicitly bound but which are annotated with
@RequestScoped
and automatically discovered by Guice.