5

Sto iniziando a utilizzare Robolectric in Android Studio. In un primo momento ho voluto creare un semplice test utilizzando hamcrest, che riportiamo di seguito:Robolectric 2.4 NoSuchMethodError non può essere trasmesso a RuntimeException durante la creazione di attività

@RunWith(CustomTestRunner.class) 
@Config(emulateSdk = 18) 
public class MainActivityTest { 

    private MainActivity mainActivity; 


    @Test 
    public void testMainActivity() { 
     mainActivity = buildActivity(MainActivity.class).create().get(); 
     assertThat(mainActivity, notNullValue()); 
    } 

} 

Quando si esegue il test genera la seguente eccezione:

java.lang.ClassCastException: java.lang.NoSuchMethodError cannot be cast to java.lang.RuntimeException 
    at org.robolectric.internal.ReflectionHelpers.callInstanceMethodReflectively(ReflectionHelpers.java:68) 
    at org.robolectric.util.ActivityController$1.run(ActivityController.java:115) 
    at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:268) 
    at org.robolectric.util.ActivityController.create(ActivityController.java:111) 
    at org.robolectric.util.ActivityController.create(ActivityController.java:122) 
    at com.enprodo.wakemethere.googleservices.geofence.GeofenceTest.testReceiver(GeofenceTest.java:31) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:158) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

La classe CustomTestRunner si presenta così:

public class CustomTestRunner extends RobolectricTestRunner { 

    public CustomTestRunner(Class<?> testClass) throws InitializationError { 
     super(testClass); 
    } 

    @Override 
    protected AndroidManifest getAppManifest(Config config) { 
     String manifestProperty = System.getProperty("android.manifest"); 
     if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) { 
      String resProperty = System.getProperty("android.resources"); 
      String assetsProperty = System.getProperty("android.assets"); 
      AndroidManifest androidManifest = new AndroidManifest(
        Fs.fileFromPath(manifestProperty), 
        Fs.fileFromPath(resProperty), 
        Fs.fileFromPath(assetsProperty)); 
      androidManifest.setPackageName("com.package"); 
      return androidManifest; 
     } 
     return super.getAppManifest(config); 
    } 
} 

Posso aggiungere che MainActivity estende android.support.v7.app.ActionBarActivity ma non ho idea se questo influisce sul comportamento.

Dopo qualche scavo nella fonte Robolectric appare l'errore si verifica quando questo viene eseguito:

ReflectionHelpers.callInstanceMethodReflectively(component, "performCreate", new ReflectionHelpers.ClassParameter(Bundle.class, bundle)); 

Il codice di callInstanceMethodReflectively assomiglia a questo:

public static <R> R callInstanceMethodReflectively(final Object instance, final String methodName, ClassParameter... classParameters) { 
    try { 
     final Class[] classes = ClassParameter.getClasses(classParameters); 
     final Object[] values = ClassParameter.getValues(classParameters); 

     return traverseClassHierarchy(instance.getClass(), NoSuchMethodException.class, new InsideTraversal<R>() { 
     @Override 
     public R run(Class traversalClass) throws Exception { 
      Method declaredMethod = traversalClass.getDeclaredMethod(methodName, classes); 
      declaredMethod.setAccessible(true); 
      return (R) declaredMethod.invoke(instance, values); 
     } 
     }); 
    } catch (InvocationTargetException e) { 
     throw (RuntimeException) e.getTargetException(); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
    } 

io non sono un esperto di riflessione, ma sembra che in qualche modo non sia possibile trovare il metodo performCreate. Qualcuno ha riscontrato problemi simili? Qualcuno ha qualche idea di quale potrebbe essere il problema?

risposta

2

Dopo un po 'di scavo sembra che con Robolectric 2.4 vengano visualizzati alcuni problemi con ActionBarActivity. In base a this issue, in Robolectric 3.0 verrà fornito il supporto completo per appcompat-v7. Infatti, provare Robolectric 3.0-SNAPSHOT ha risolto il problema.