14

我的 Android 应用程序有一个简单的方法来触发显示 URL 的意图。

protected void launchBrowser(int id)
{
    Uri uri = Uri.parse( getString( id ) );
    Intent intent = new Intent( ACTION_VIEW, uri);

    PackageManager packageManager = getPackageManager();
    List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
    if (activities.size() > 0)
    {
        startActivity(intent);
    }
    else
    {
        Toast.makeText(getApplicationContext(),
                       "ERROR - no application to display a web page",
                       Toast.LENGTH_SHORT).show();
    }
}

我正在使用 Robolectric 进行单元测试,但我无法验证此方法。具体来说,getPackageManager()总是返回 null。我怎样才能阴影PackageManager?我尝试创建一个ShadowPackageManager并调用bindShadowClass,但我的代码都没有被执行——getPackageManager()总是返回null。我还尝试隐藏 Application 上下文并返回一个具体的StubPackageManager,但得到了相同的结果。也许我一直在搜索/盯着太久 - 有没有更好的方法来单元测试这个方法?

4

6 回答 6

9

我为此使用 Robolectric 2.3。如其他答案所述,getPackageManager()不返回 null,但shadowApplication.setPackageManager不再存在。

由于你不能 mock PackageManager,你不能给它一个Intents要解决的列表。幸运的是,Robolectric 的PackageManager子类RobolectricPackageManager可以让您在没有模拟的情况下添加这些意图:

RobolectricPackageManager rpm = (RobolectricPackageManager)Robolectric.application.getPackageManager();
rpm.addResolveInfoForIntent(new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS), new ResolveInfo());
于 2014-06-15T21:18:56.730 回答
7

出于某种原因,您需要在您的应用程序上手动设置影子包管理器。创建一个自定义测试运行器(通过扩展 RobolectricTestRunner)并覆盖 setApplicationState 方法:

public class MyTestRunner extends RobolectricTestRunner {   
  @Override
  public void setupApplicationstate(RobolectricConfig robolectricConfig) {
     super.setupApplicationState(robolectricConfig);
     ShadowApplication shadowApplication = shadowOf(Robolectric.application);
     shadowApplication.setPackageName(robolectricConfig.getPackageName());
     shadowApplication.setPackageManager(new RobolectricPackageManager(Robolectric.application, robolectricConfig));
  }
}

然后在你的测试中指定你想使用你自己的测试运行器:

@RunWith(MyTestRunner.class)
public class MyTest { ... }
于 2012-10-17T00:20:22.540 回答
3

只需添加到aleph_null的答案,您就可以使用它ShadowResolveInfo.newResolveInfo()来快速创建一个ResolveInfo可供使用的模拟(我使用的是 Robolectric 2.4)。

RobolectricPackageManager rpm = (RobolectricPackageManager)Robolectric.application.getPackageManager();
rpm.addResolveInfoForIntent(new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS), ShadowResolveInfo.newResolveInfo(...));
于 2015-01-31T17:15:32.213 回答
3

我升级到最新的 Robolectric(2.1.1 版),PackageManagernull不再出现。

下面的代码验证是否触发了浏览器意图(并配置了 url)。我还没有在 1.x 上测试过这个,但我认为它也可以在那里工作:

@Test
public void recipeTitleShouldOpenBrowserOnClick() throws Exception
{
    title.performClick();
    ShadowActivity shadowActivity = shadowOf( detailFragment.getActivity() );
    ShadowActivity.IntentForResult intent = shadowActivity.peekNextStartedActivityForResult();

    // or
    // ShadowActivity.IntentForResult intent = shadowActivity.getNextStartedActivityForResult();

    assertThat( intent.intent,
                equalTo( createBrowserIntentWithURL( "url" ) ) );
}

注意:我在这里从一个片段调用启动活动。

于 2013-06-13T16:46:07.730 回答
1

您可以在单独的方法中设置 ShadowPackageManager(无需扩展 RobolectricTestRunner)

private void setupPackageManager() {
    ShadowApplication shadowApplication = shadowOf(Robolectric.application);
    shadowApplication.setPackageManager(mockPackageManager);
    List<ResolveInfo> activities = new ArrayList<ResolveInfo>();
    activities.add(resolveInfo("com.test.package.Class1"));
    activities.add(resolveInfo("com.test.package.Class2"));
    when(mockPackageManager.queryIntentActivities(any(Intent.class), anyInt())).thenReturn(activities);
}

注意:在这里,我使用了 mockito 并为我的单元测试模拟了 packagemanager,而不是使用实际的 PackageManager。

于 2013-06-09T05:57:59.550 回答
1

对于 Robolectric 3.1,您可以

RobolectricPackageManager packageManager = RuntimeEnvironment.getRobolectricPackageManager();
// add necessary logic here
于 2016-11-17T13:55:22.823 回答