I use Robolectric for unit tests, I have Google Play Services in my project. This worked fine, until yesterday, when Google Play Services updated to a new version. I get this error:
java.lang.NullPointerException
at com.google.android.gms.common.GooglePlayServicesUtil.zzh(Unknown Source)
at com.google.android.gms.common.GooglePlayServicesUtil.zzd(Unknown Source)
at com.google.android.gms.common.GoogleApiAvailability.isGooglePlayServicesAvailable(Unknown Source)
at com.google.android.gms.common.api.zzg$zze.zznn(Unknown Source)
at com.google.android.gms.common.api.zzg$zzi.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Process finished with exit code 255
It seems the Shadow class is not called, GooglePlayServicesUtil is called giving the NullPointerException. Has anyone seen this?
I don't even use Google Play Services in the tests.
I've added next workaround and it works fine:
Extract all PlayServices' related code to Utility class (in my case it is just Availability check):
public class PlayServicesUtils {
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
public static final int AVAILABLE = 1;
public static final int ERROR_RESOLVABLE = 2;
public static final int ERROR_UNRESOLVABLE = 3;
@IntDef({AVAILABLE, ERROR_RESOLVABLE, ERROR_UNRESOLVABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayServicesAvailability {
}
@PlayServicesAvailability
public static int checkPlayServices(@NonNull Activity activity) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(activity);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(activity, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show();
return PlayServicesUtils.ERROR_RESOLVABLE;
} else {
CLog.e(Constants.TAG, "This device does not support Google Play services.");
return PlayServicesUtils.ERROR_UNRESOLVABLE;
}
}
return PlayServicesUtils.AVAILABLE;
}
}
Implement shadow for this Utility class:
@Implements(PlayServicesUtils.class)
public class ShadowPlayServicesUtils {
@Implementation
@PlayServicesUtils.PlayServicesAvailability
public static int checkPlayServices(@NonNull Activity activity) {
return PlayServicesUtils.AVAILABLE;
}
}
Add shadow to your test class (or to base level test class):
@Ignore
@RunWith(TestRunner.class)
@Config(
sdk = 18,
constants = BuildConfig.class,
shadows = {
ShadowPlayServicesUtils.class
}
)
public abstract class BaseTest {
// some code, maybe
}
Add your shadow to TestRunner's InstrumentationConfiguration creation:
public class TestRunner extends RobolectricGradleTestRunner {
public TestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
public InstrumentationConfiguration createClassLoaderConfig() {
InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder();
builder.addInstrumentedClass(PlayServicesUtils.class.getName());
return builder.build();
}
}
Original answer:
I've found similar issue on Robolectric issue tracker and workaround which is provided there - works!
Just force success initialisation of Google Play Services:
@Before public void setUp() {
// force success every time
ShadowGooglePlayServicesUtil.setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
}
EDIT:
But there is another issue with Play Services 8.3 and 8.4. And this issue is still not fixed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With