Как я могу скрыть PackageManager с помощью 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
. Я также попытался применить тень контекста приложения и вернуть конкретный StubPackageManager
, но получил те же результаты.
Возможно, я слишком долго искал/смотрел - есть ли лучший способ unit test использовать этот метод?
Ответы
Ответ 1
Я использую 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());
Ответ 2
По какой-то причине вам необходимо вручную установить теневой упаковщик вручную.
Создайте собственный тестовый бегун (путем расширения 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 { ... }
Ответ 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" ) ) );
}
Примечание. Я вызываю начальную активность из фрагмента здесь.
Ответ 4
Просто добавьте в ответ 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(...));
Ответ 5
Вы можете установить 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 для моего unittest вместо использования фактического PackageManager.
Ответ 6
Для Robolectric 3.1 вы можете
RobolectricPackageManager packageManager = RuntimeEnvironment.getRobolectricPackageManager();
// add necessary logic here