I am trying to write some tests for an existing application. I wanted to supply a test Application class to the tests and I followed the example here, since I am also using Dagger for DI.
However, if the activity under test is an ActionBarActivity, I get the following exception:
java.lang.IllegalArgumentException: android.content.pm.PackageManager$NameNotFoundException: ComponentInfo{mypackage.view.activity/mypackage.view.activity.MyActivity}
at android.support.v4.app.NavUtils.getParentActivityName(NavUtils.java:282)
at android.support.v7.app.ActionBarActivityDelegate.onCreate(ActionBarActivityDelegate.java:116)
at android.support.v7.app.ActionBarActivityDelegateICS.onCreate(ActionBarActivityDelegateICS.java:57)
at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.java:98)
at mypackage.view.activity.MyActivity.onCreate(MyActivity.java:68)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.test.ActivityUnitTestCase.startActivity(ActivityUnitTestCase.java:158)
at mypackage.MyActivityTest.test(MyActivityTest.java:89)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)
Caused by: android.content.pm.PackageManager$NameNotFoundException: ComponentInfo{mypackage.view.activity/mypackage.view.activity.MyActivity}
at android.app.ApplicationPackageManager.getActivityInfo(ApplicationPackageManager.java:242)
at android.support.v4.app.NavUtils.getParentActivityName(NavUtils.java:298)
at android.support.v4.app.NavUtils.getParentActivityName(NavUtils.java:279)
... 21 more
My test class looks like follows:
public class MyActivityTest extends ActivityUnitTestCase<MyActivity> {
...
public MyActivityTest() {
super(MyActivity.class);
}
private Context context;
private TestBaseApplication application;
@Override
protected void setUp() throws Exception {
super.setUp();
context = new ContextThemeWrapper( getInstrumentation().getTargetContext(), R.style.Theme_AppCompat){
@Override
public Context getApplicationContext() {
return application;
}
};
application = new TestBaseApplication( context);
setApplication(application);
...
}
public void test() throws InterruptedException {
setActivityContext( context);
Intent intent = new Intent( context, MyActivity.class);
startActivity(intent, null, null);
...
}
}
The activity appears in the AndroidManifest as follows:
<activity
android:name=".view.activity.MyActivity"
android:icon="@drawable/actionbar_logo"
android:screenOrientation="portrait"
android:parentActivityName="mypackage.ParentActivity">
<meta-data android:name="android.support.PARENT_ACTIVITY"
android:value="mypackage.ParentActivity"/>
</activity>
After some troubleshooting, I tried running the example at the link above and it works just fine, even when I change the activity to extend ActionBarActivity.
Since I wasn't able to find the cause of the problem, I also played around with the manifest, build.gradle, etc. Now, I am just stuck with this and I cannot think of anything else.
This post may also be close to related to the problem, but there is not any comment on that one either. And this post also seemed to have similar problem but the solution there doesn't work me as I don't want the real application to be launched with the activity.
EDIT:
I've created a simple separate project, in order to isolate the issue.
First I've written an ActivityUnitTestCase for an Activity which extends ActionBarActivity. It worked fine.
After that, I've tried adding few more activities, making them parent of each other.( so that it looks like my actual project). And that worked fine too.
Lastly, I've added more ActivityUnitTestCase classes with different activities from my actual project, all extending ActionBarActivity, with same setup for all of them , and run the tests on two devices, one being an emulator (Genymotion) and the other is my physical device. (Nexus 4)
Tests all gave the NameNotFoundException on the emulator. All but one of the tests passed on the physical device, which made me even more confused.
It all comes down to this bug in
ActivityUnitTestCase
.Activities built using
ActivityUnitTestCase.startAcitvity()
have a componentName pointing to the application package. So whenActionBarActivity
checks for a parent activity to update the Up symbol, the test crashes if the activity is not in the app 'root' package.Fortunately the workaround proposed in the issue description works just fine, so until this is fixed, just make a local copy of
ActivityUnitTestCase
, update the line in which the componentName is defined as below, and make sure your test cases extend that class instead of the originalActivityUnitTestCase
.