Problem with Robolectric with the new version of Google Play services

I use Robolectric for unit tests, I have Google Play Services in my project. This worked fine until yesterday, when Google Play Services upgraded to the 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 that the Shadow class is not called, the GooglePlayServicesUtil method is called, which throws a NullPointerException. Has anyone seen this?

I don’t even use Google Play services in tests.

+7
android google-play-services robolectric
source share
1 answer

I added the following workaround and it works fine:

  • Extract all the associated PlayServices code into the Utility class (in my case, this is an 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 a shadow to your test class (or to a 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 a shadow to the TestRunner InstrumentationConfiguration:

     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 found a similar problem in the Robolectric search engine and the workaround that is provided there - works!

Just run a successful initialization of Google Play services.

 @Before public void setUp() { // force success every time ShadowGooglePlayServicesUtil.setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS); } 

EDIT:

But there is still an issue with Play Services 8.3 and 8.4. And this problem is still not fixed.

+4
source share

All Articles