2015-08-17 18 views
7

Uso Robolectric per i test di unità, nel mio progetto ho Google Play Services. Questo ha funzionato fino a ieri, quando Google Play Services è stato aggiornato a una nuova versione. Ottengo questo errore:Problema con Robolectric con la nuova versione dei servizi Google Play

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 

Sembra la classe Ombra non si chiama, si chiama GooglePlayServicesUtil dando la NullPointerException. Qualcuno ha visto questo?

Non utilizzo nemmeno Google Play Services nei test.

+0

L'eccezione NullPointerException è principalmente quando la classe non è in ombra. Quando ricevi questo errore? È durante l'esecuzione del test case o è quando la configurazione dell'applicazione viene caricata prima del test? – Kanishk

+0

So che non è in ombra. Esiste una classe shadow per GooglePlayServicesUtil e, come fino a ieri, ha funzionato bene, è stata visualizzata prima di ieri. Ho cercato di scoprire se Robolectric dipende da una versione specifica del GPS, non l'ho trovato. – Christine

+0

Penso che puoi segnalare questo problema in 'Roblectric' [qui] (https://github.com/robolectric/robolectric/issues) o tracker di problemi Android [qui] (https://code.google.com/pp/android/issues/list) – bjiang

risposta

4

Ho aggiunto la prossima soluzione e funziona benissimo:

  1. estratto tutti PlayServices' relativi codice alla classe di utilità (nel mio caso si tratta solo di Controllo disponibilità):

    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; 
        } 
    } 
    
  2. Implementare ombra per questa classe di utilità:

    @Implements(PlayServicesUtils.class) 
    public class ShadowPlayServicesUtils { 
    
        @Implementation 
        @PlayServicesUtils.PlayServicesAvailability 
        public static int checkPlayServices(@NonNull Activity activity) { 
         return PlayServicesUtils.AVAILABLE; 
        } 
    } 
    
  3. Aggiungi ombra alla classe di test (o alla base livello di prova di classe):

    @Ignore 
    @RunWith(TestRunner.class) 
    @Config(
         sdk = 18, 
         constants = BuildConfig.class, 
         shadows = { 
           ShadowPlayServicesUtils.class 
         } 
    ) 
    public abstract class BaseTest { 
        // some code, maybe 
    } 
    
  4. Aggiungi la tua ombra alla creazione InstrumentationConfiguration di TestRunner:

    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(); 
        } 
    } 
    

risposta originale:

Ho trovato similar issue su tracker di problemi Robolectric e lavoro intorno a cui è fornito lì - funziona!

Proprio forzare successo inizializzazione di Google Play Services:

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

EDIT:

Ma c'è un altro issue con Play Services 8.3 e 8.4. E questo problema non è ancora stato risolto.

+0

Grazie mille. Fino a quando risolvono il problema con la versione 8.4, questo funziona alla grande! –

+0

@ShobhitPuri sei il benvenuto! – Oleksandr

+0

Non riesco a utilizzare questa soluzione poiché l'ultimo robolectric ha cambiato l'api in modo che non venga compilato (i nostri test dipendono dalla nuova versione).Ecco la mia domanda su come implementare questo con il nuovo, si prega di dare un'occhiata: https://stackoverflow.com/questions/48123570/ – Gabor

Problemi correlati