2015-03-17 10 views
9

Sto provando a eseguire i test di unità usando Robolectric; corrono bene con Android Studio, ma gli stessi test non riescono a funzionare correttamente nella riga di comando - il che è un grosso problema, devo essere in grado di eseguirli dalla mia piattaforma di integrazione continua, non solo da un IDE.Test di Robolectric in esecuzione su Android Studio ma non sulla riga di comando

Ho il sospetto che manchi un argomento della riga di comando (ad esempio un classpath o qualcosa di simile) o che richiami l'attività sbagliata, altrimenti il ​​test non verrebbe eseguito da Android Studio. Alcuni dettagli rilevanti; il test è simile al seguente:

@RunWith(RobolectricTestRunner.class) 
@Config(manifest = "app/src/main/AndroidManifest.xml", resourceDir = "res", emulateSdk = 19) 
public class SplashActivityTest { 

    @Test 
    public void testActivity() { 
     SplashActivity splashActivity = new SplashActivity(); 
     String appName = splashActivity.getString(R.string.app_name); // HERE, line 20 
     assertEquals(appName, "App"); 
    } 

} 

Come accennato in precedenza, funziona benissimo in Android Studio (facendo clic destro sul file di test e selezionando Run 'SplashActivityTest'), ma quando si esegue dalla riga di comando non riesce nella linea contrassegnata con HERE, con la seguente analisi dello stack:

android.content.res.Resources$NotFoundException: unknown resource 2131492893 
    at org.robolectric.shadows.ShadowAssetManager.getAndResolve(ShadowAssetManager.java:309) 
    at org.robolectric.shadows.ShadowAssetManager.getResourceText(ShadowAssetManager.java:69) 
    at android.content.res.AssetManager.getResourceText(AssetManager.java) 
    at android.content.res.Resources.getText(Resources.java:240) 
    at org.robolectric.shadows.ShadowResources.getText(ShadowResources.java:361) 
    at android.content.res.Resources.getText(Resources.java) 
    at android.content.res.Resources.getString(Resources.java:330) 
    at org.robolectric.shadows.ShadowContext.getString(ShadowContext.java:39) 
    at org.robolectric.shadows.ShadowContextWrapper.getString(ShadowContextWrapper.java:69) 
    at android.content.Context.getString(Context.java) 
    at path.to.myApp.activities.SplashActivityTest.testActivity(SplashActivityTest.java:20) 
    // ... and so on ... 

sto usando questo per eseguire dalla riga di comando (si noti che qui e in Android Studio che sto utilizzando l'involucro Gradle):

project-root$ ./gradlew test --continue 

anche: sto usando Android Studio 1.1.0, versione Gradle è 2.3, la versione di Robolectric è 3.0-SNAPSHOT e la versione plug-in Gradle di Robolectric è 1.0.1

+0

Oscar, si può eseguire con l'opzione '--debug'. Mi aspetto che vedrai il messaggio relativo al problema per trovare il file manifest e utilizzando quello predefinito –

+0

@EugenMartynov Sei sulla strada giusta, ottengo questo sulla console: 'ATTENZIONE: nessun file manifest trovato su ./app/src/ principale/AndroidManifest.xml. Ritornando alle sole risorse del sistema operativo Android. Puoi elaborare? –

risposta

8

Si scopre che si tratta di un problema noto. Le risorse di un progetto vengono cercate nella directory sbagliata quando si eseguono i test dalla riga di comando, ecco un problema link; per ora la soluzione è quella di scrivere un test runner personalizzata come dimostrato here:

public class RobolectricGradleTestRunner extends RobolectricTestRunner { 

    public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError { 
     super(testClass); 
     String buildVariant = (BuildConfig.FLAVOR.isEmpty() ? "" : BuildConfig.FLAVOR+ "/") + BuildConfig.BUILD_TYPE; 
     String intermediatesPath = BuildConfig.class.getResource("").toString().replace("file:", ""); 
     intermediatesPath = intermediatesPath.substring(0, intermediatesPath.indexOf("/classes")); 

     System.setProperty("android.package", BuildConfig.APPLICATION_ID); 
     System.setProperty("android.manifest", intermediatesPath + "/manifests/full/" + buildVariant + "/AndroidManifest.xml"); 
     System.setProperty("android.resources", intermediatesPath + "/res/" + buildVariant); 
     System.setProperty("android.assets", intermediatesPath + "/assets/" + buildVariant); 
    } 

} 

I casi di test devono essere aggiornati di conseguenza utilizzare il test corridore personalizzato invece di del @Config annotazione:

@RunWith(RobolectricGradleTestRunner.class) 
public class SplashActivityTest { 
    // tests same as before 
} 

Inoltre, si consiglia di eseguire un clean quando si eseguono i test dalla riga di comando, dato che la soluzione alternativa dipende dal contenuto della directory di build, non vogliamo avere i dati non aggiornati:

project-root$ ./gradlew clean test --continue 
+0

Proprio come un addendum a questa risposta.A partire dal 2014/04/24, mi consiglia di utilizzare la libreria più recente ** Robolectric 3.0-SNAPSHOT **. Questa istantanea ha un built-in ** RobolectricGradleTestRunner ** che funzionerà anche con gli elementi BuildVariant (Flavor, Type, ecc.). Con questo, non è necessario scrivere da solo un corridore di prova. Per il corridore aggiornato [una classe di configurazione costante può essere definita come questa] (https://github.com/robolectric/robolectric/blame/master/robolectric/src/test/java/org/robolectric/RobolectricGradleTestRunnerTest.java#L67) . – abest

+3

@abest ha ancora problemi con l'esecuzione di test su un mac – jonney

0

Ho risolto lo stesso errore, ma in modo diverso. Ho usato le ombre di classe personalizzati nei test, quindi devo creare il mio classe TestRunner, in questo modo:

public class MyRobolectricTestRunner extends RobolectricTestRunner { 

    public MyRobolectricTestRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    public InstrumentationConfiguration createClassLoaderConfig() { 
     InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder(); 
     builder.addInstrumentedClass(AppUtils.class.getName()); 
     return builder.build(); 
    } 
} 

Ma soprattutto il codice funzionava solo quando faccio funzionare l'unità-test dal Andorid studio. Si prega, controlla codice che funziona per me in entrambi i modi: in Studio e dalla riga di comando:

public class MyRobolectricTestRunner extends RobolectricTestRunner { 

    public MyRobolectricTestRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    public InstrumentationConfiguration createClassLoaderConfig() { 
     InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder(); 
     builder.addInstrumentedPackage(com.example.stackoverflow.AppUtils.class.getPackage().getName()); 
     return builder.build(); 
    } 
} 

Si prega di notare che ho la dipendenza:

testCompile 'org.robolectric:robolectric:3.0'