ActivityUnitTestCase中的NameNotFoundException与ActionBarActivity相关。

7
我正在尝试为一个现有应用程序编写一些测试。我想为测试提供一个测试应用程序类,并按照这里的示例操作,因为我也在使用Dagger进行依赖注入。
然而,如果被测试的活动是ActionBarActivity,则会出现以下异常:
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

我的测试类如下所示:

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

活动在AndroidManifest中的表现如下:
<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>

经过一些故障排除后,我尝试运行上面链接中的示例,即使我将活动更改为扩展ActionBarActivity,它也可以正常工作。
由于我无法找到问题的原因,我还玩弄了清单、build.gradle等。现在,我只是卡在这里,无法想到其他任何办法。 此帖子 也可能与问题接近,但那个帖子上没有任何评论。而 这篇文章 似乎也有类似的问题,但那里的解决方案对我不起作用,因为我不想使用该活动启动真实应用程序。 编辑
我创建了一个简单的独立项目,以便隔离问题。
首先,我为扩展ActionBarActivity的Activity编写了一个ActivityUnitTestCase。它很好地工作了。
之后,我尝试添加更多活动,使它们相互父级(以便看起来像我的实际项目)。那也很好运行。
最后,我已经添加了更多的ActivityUnitTestCase类,这些类都是从我的实际项目中提取的不同活动,并且都扩展了ActionBarActivity。对于所有这些测试用例,我都设置了相同的设置,并在两个设备上运行了测试,一个是模拟器(Genymotion),另一个是我的物理设备(Nexus 4)。
测试在模拟器上都出现了NameNotFoundException异常。在物理设备上,除了一个测试用例之外,其他测试用例都通过了,这让我更加困惑。

1
如果我要猜的话,这可能是AppCompat查找父活动的方式中出现的错误,只有在使用来自测试工具的Context时才会出现。但这只是一个猜测。您可以尝试创建一个小型独立项目(和测试),以查看是否可以在隔离环境中重现它。如果可以,并且您确定您正在使用最新版本的appcompat-v7,请在问题跟踪器上提交带有示例项目和堆栈跟踪的问题。 - CommonsWare
@CommonsWare:感谢您的评论。我已经更新了我的帖子,并加入了您的建议结果。可能会像您所说的那样存在错误,但是在单独的项目中肯定无法重现它,以便我可以提交问题。 - Emre Dirican
不幸的是,这也限制了任何人的帮助能力,因为我们也不太可能复现它。 :-( - CommonsWare
1个回答

10

所有问题都归结于ActivityUnitTestCase中的bug

使用ActivityUnitTestCase.startAcitvity()构建的活动具有指向应用程序包的componentName。因此,当ActionBarActivity检查父活动以更新Up符号时,如果该活动不在应用程序“root”包中,则测试将崩溃。

幸运的是,问题描述中提出的解决方法非常有效,因此在修复此问题之前,只需创建ActivityUnitTestCase的本地副本,更新定义componentName的行如下,并确保您的测试用例扩展该类而不是原始的ActivityUnitTestCase

// replace this line
new ComponentName(mActivityClass.getPackage().getName(), mActivityClass.getName());

// with this
new ComponentName(getInstrumentation().getTargetContext(), mActivityClass);

1
谢谢,这真的帮了我。 :) 我只是复制了ActivityUnitTestCase并将该行更改为“ComponentName cn = new ComponentName(getInstrumentation().getTargetContext(), mActivityClass);” - scrrr
或者您可以将该活动移动到根包中,但这种解决方案可能不是最理想的。 - DJ_Polly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接