1

I have to deal with some legacy code. There is one point where I need a function like

NewCodeAccessor.get() which gives me an object that is obtained from Guice.

public class NewCodeAccessor {
    @Inject
    public static Provider<PageDataHandle> pageDataHandleProvider;

    public static PageDataHandle get() {
        return pageDataHandleProvider.get();
    }
}

Guice is initialized earlier and a static injection on this class is requested.

In production code this works fine, but now I try to test it. PageDataHandle is request scoped, so my test looks like this:

@Before
public void setUp() {
    Injector createInjector = Guice.createInjector(new ServletModule(), 
        new AppModule());
}

@Test
public void testGetInjector() throws Exception {

    // put it inside a callable to wrap it in a request scope, as it would
    // usually be done in a request on the server
    Callable<PageDataHandle> scopeRequest = ServletScopes.scopeRequest(
            new Callable<PageDataHandle>() {
                @Override
                public PageDataHandle call() throws Exception {
                    PageDataHandle data = NewCodeAccessor.get();
                    return data;
                }
            }, Collections.<Key<?>, Object> emptyMap());
    PageDataHandle data = scopeRequest.call();
    assertTrue(data != null);
}

This still works, as long as PageDataHandle or it's dependencies doesn't requests a injection for the request parameters:

@Inject @RequestParameters Map<String, String[]> requestParameters

Here I get an OutOfScope Exception: com.google.inject.ProvisionException: Guice provision errors:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped >object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten >to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

I tried to add my own test module with something like this:

bind(new TypeLiteral<Map<String, String[]>>() {
    }).annotatedWith(com.google.inject.servlet.RequestParameters.class)
    .toInstance(parameters);

But this doesn't work because RequestParameters is already bound by ServletRequest.

What I could do is the following: I leave out the ServletModule in the injector I create for my test and bind RequestScope to my own, custom scope. Then RequestParameters wouldn't be bound by anyone else, so I could create my own binding to mock that. But that doesn't seem nice. Could anyone tell me how to do this properly? Thanks!

jcvj
  • 130
  • 8

1 Answers1

0

I would definitely recommend avoiding the ServletModule during tests (except for integration tests). The alternative is to do ServletScopes.scopeRequest() which will create a fake request scope for you.

Tavian Barnes
  • 12,477
  • 4
  • 45
  • 118
  • Thanks for your answer, but it IS an integration test and, as written, I'm already using the `ServletScopes.scopeRequest()` Method. But I kind of solved the problem. I now put the `@RequestParameters` thing in an other class which I then mocked away. Not really a satisfying solution but at least something. – jcvj Jul 08 '13 at 20:36