如何使用Robolectric对PackageManager进行阴影处理

时间:2012-10-15 19:38:08

标签: android shadow robolectric

我的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。我还尝试了Shadow the Application上下文并返回一个具体的StubPackageManager,但得到了相同的结果。 也许我一直在寻找/盯着太久 - 有没有更好的方法对这种方法进行单元测试?

6 个答案:

答案 0 :(得分:9)

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

由于您无法模拟PackageManager,因此无法为其提供要解析的Intents列表。幸运的是,Robolectric的PackageManager子类RobolectricPackageManager可以让你在没有模拟的情况下添加这些意图:

RobolectricPackageManager rpm = (RobolectricPackageManager)Robolectric.application.getPackageManager();
rpm.addResolveInfoForIntent(new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS), new ResolveInfo());

答案 1 :(得分:7)

出于某种原因,您需要在应用程序上手动设置shadow packagemanager。 创建自定义测试运行器(通过扩展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 { ... }

答案 2 :(得分:3)

我升级到最新的Robolectric(版本2.1.1),而PackageManager不再出现null

下面的代码验证是否触发了浏览器意图(并使用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" ) ) );
}

注意:我在这里调用片段的开始活动。

答案 3 :(得分: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(...));

答案 4 :(得分: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&amp;为我的unittest嘲笑packagemanager而不是使用实际的PackageManager。

答案 5 :(得分:1)

对于Robolectric 3.1,您可以

RobolectricPackageManager packageManager = RuntimeEnvironment.getRobolectricPackageManager();
// add necessary logic here