Sarpe
Sarpe

Reputation: 5806

Android Testing with Robolectric ClassCastException: android.app.Application cannot be cast to MyApplication

I'm testing my android App with Robolectric and I'm struggling with this cast :

 MyModel myModel = ((MyApplication) context.getApplicationContext()).getMyModel;

Apparently Robolectric is complaining with this error:

 java.lang.RuntimeException: java.lang.ClassCastException: android.app.Application cannot be cast to com.reply.delhaize.common.DelhaizeApplication
    at org.robolectric.util.SimpleFuture.run(SimpleFuture.java:57)
    at org.robolectric.shadows.ShadowAsyncTask$2.run(ShadowAsyncTask.java:95)
    at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:37)
    at org.robolectric.util.Scheduler.post(Scheduler.java:42)
    at org.robolectric.shadows.ShadowAsyncTask.execute(ShadowAsyncTask.java:92)
    at android.os.AsyncTask.execute(AsyncTask.java)
    at com.reply.delhaize.common.models.StoreModel.getStoreList(StoreModel.java:617)
    at com.reply.delhaize.common.models.StoreModel.fetchAllStores(StoreModel.java:107)
    at com.reply.delhaize.core.tests.storefinder.StoreFinderTest.fetchAllStoresWhenWifiIsOn(StoreFinderTest.java:84)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:175)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassCastException: android.app.Application cannot be cast to com.reply.delhaize.common.DelhaizeApplication
    at com.my.package.name.models.GetApiModelTaskOtto.doInBackground(GetApiModelTaskOtto.java:74)
    at com.my.package.name.models.GetApiModelTaskOtto.doInBackground(GetApiModelTaskOtto.java:1)
    at android.os.ShadowAsyncTaskBridge.doInBackground(ShadowAsyncTaskBridge.java:14)
    at org.robolectric.shadows.ShadowAsyncTask$BackgroundWorker.call(ShadowAsyncTask.java:149)
    at org.robolectric.util.SimpleFuture.run(SimpleFuture.java:52)
    at org.robolectric.shadows.ShadowAsyncTask$2.run(ShadowAsyncTask.java:95)
    at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:37)
    at org.robolectric.util.Scheduler.post(Scheduler.java:42)
    at org.robolectric.shadows.ShadowAsyncTask.execute(ShadowAsyncTask.java:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:456)
    at android.os.AsyncTask.execute(AsyncTask.java)
    at com.my.package.name.models.StoreModel.getStoreList(StoreModel.java:617)
    at com.my.package.name.models.StoreModel.fetchAllStores(StoreModel.java:107)
    at com.reply.delhaize.core.tests.storefinder.StoreFinderTest.fetchAllStoresWhenWifiIsOn(StoreFinderTest.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    ... 22 more

I would like to find a proper way to test it.

I have declared MyApplication in the manifest:

   <application
    android:name="com.my.package.name.MyApplication"
    android:allowBackup="false"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    ......

and these are the tests

        @RunWith(RoboletricTestRunner.class)
        public class StoreFinderTest extends BaseTest {


    StoreListActivity storeListActivity;
    StoreModel storeModel;
    UserModel userModel;

 @Before
public void setUp() throws Exception {

    storeListActivity = Robolectric.buildActivity(StoreListActivity.class).get();
    storeModel = new StoreModel(storeListActivity.getApplicationContext());
    userModel = new UserModel(storeListActivity.getApplicationContext());

}

@Test
public void activityExists() {

     assertThat(storeListActivity).isNotNull();
}


   @Test
public void fetchAllStoresWhenWifiIsOn() {      

ConnectivityManager cm =(ConnectivityManager)Robolectric.application.getSystemService(Context.CONNECTIVITY_SERVICE);

    Robolectric.shadowOf(cm).setNetworkInfo(ConnectivityManager.TYPE_WIFI, cm.getActiveNetworkInfo()); 

    boolean result = storeModel.fetchAllStores();
    assertTrue(result);
}

storeModel.fetchAllStores() implementation has this ugly cast:

     MyModel myModel = ((MyApplication) context.getApplicationContext()).getMyModel;

So is there a way for testing with Robolectric portion of code that contains cast like this ?

     ((MyApplication) context.getApplicationContext())

Upvotes: 4

Views: 4766

Answers (3)

Tonnie
Tonnie

Reputation: 8142

Encountered the same error;

java.lang.ClassCastException: androidx.test.runner.AndroidJUnitRunner cannot be cast to org.robolectric.android.fakes.RoboMonitoringInstrumentation

I realized I was using the wrong implementation for Roboelectric:

 implementation "org.robolectric:robolectric:4.5.1"

If you are using this please replace it with testImplementation instead:

testImplementation "org.robolectric:robolectric:$robolectricVersion"

Upvotes: 0

Suraj C
Suraj C

Reputation: 462

You may need to specify the path to your AndroidManifest.xml for your test. You can do so using as follows:

@Config(manifest = "/path/to/your/AndroidManifest.xml")
@RunWith(RoboletricTestRunner.class)
public class StoreFinderTest extends BaseTest {
...
}

You can make Robolectric use a test version of your application by simply creating a TestMyApplication class (i.e. class with prefix "Test" before the name of your application class) in the same package as your MyApplication in the test directory of your project. To work around your casting problem, TestMyApplication should extend MyApplication:

public class TestMyApplication extends MyApplication {
}

Upvotes: 5

cptKopernikus
cptKopernikus

Reputation: 72

I don't know Robolectric but maybe add an
if(context.getApplicationContext() instanceof MyApplication
statement

Upvotes: -3

Related Questions