I’ve written a JUnit (4.10) unit test that makes the following call to com.google.appengine.api.ThreadManager:
ThreadManager.currentRequestThreadFactory();
When this test runs, I get a NullPointerException being thrown from within this currentRequestThreadFactory method:
Caused by: java.lang.NullPointerException
at com.google.appengine.api.ThreadManager.currentRequestThreadFactory(ThreadManager.java:39)
at com.myapp.server.plumbing.di.BaseModule.providesThreadFactory(BaseModule.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
When I pull down the source for ThreadManager, and look at Line 39 (which is the source of the NPE), I see:
public static ThreadFactory currentRequestThreadFactory() {
return (ThreadFactory) ApiProxy.getCurrentEnvironment().getAttributes()
.get(REQUEST_THREAD_FACTORY_ATTR);
}
So it seems that the ApiProxy.getCurrentEnvironment() is null, and when it’s getAttribute() method is called, the NPE is thrown. I’ve confirmed this by adding some new print statements higher up in my unit test code:
if(ApiProxy.getCurrentEnvironment() == null)
System.out.println("Environment is null.");
I’m vaguely aware that GAE offers “test versions” for all its services, but haven’t been able to find (specifically) how to use them and set them up. So I ask: does GAE offer such test versions? If so, how do I add an ApiProxy test version here? And if not, then what are my options? I don’t think I can mock either method (ThreadManager#currentRequestThreadFactory or ApiProxy#getCurrentEnvironment) because they’re both statics. Thanks in advance.
Edit: I see that there is an appengine-testing.jar that ships with the SDK. Inside this JAR is an ApiProxyLocal.class that I believe is a version of ApiProxy that could be used during JUnit testing, that would work without throwing the NPE. If that’s the case (which I’m not even sure of), then the question is: how do I inject it into my ThreadManager for this test?
I suggest avoiding calling
ThreadManager.currentRequestThreadFactory()directly from your code. Instead, inject theThreadFactoryinto the class that needs to create threads.One easy way to do this is with Guice:
In your tests for
MyService, you could either pass a fakeThreadFactoryto theMyServiceconstructor or injectExecutors.defaultThreadFactory().In your production code, you would create a binding:
Of course, if you’re not ready to jump into dependency injection, you can create your own accessors to get and set the
ThreadFactory