Clean up test with Robolectric's way to launch a fragment with an

activity.

Robolectric has shadows for many Android framework's code. With the help
of Robolectric, We don't need
to use mock the return value of every method Activity or Fragment has.

Bug: 283885638
Test: atest AccessibilityDetailsSettingsFragmentTest

Change-Id: I77dfa755e3a1b6a240a06f74b5a6c5984534c831
This commit is contained in:
Chun-Ku Lin
2023-05-23 17:32:44 +00:00
parent 53c0788cc9
commit f4d7518710
2 changed files with 85 additions and 70 deletions

View File

@@ -22,13 +22,9 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -36,27 +32,25 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.google.common.collect.ImmutableList;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowAccessibilityManager; import org.robolectric.shadows.ShadowAccessibilityManager;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
@@ -64,112 +58,116 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** Tests for {@link AccessibilityDetailsSettingsFragment}. */ /** Tests for {@link AccessibilityDetailsSettingsFragment}. */
@Config(shadows = ShadowFragment.class) @Config(shadows = ShadowDevicePolicyManager.class)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class AccessibilityDetailsSettingsFragmentTest { public class AccessibilityDetailsSettingsFragmentTest {
private final static String PACKAGE_NAME = "com.foo.bar"; private static final String PACKAGE_NAME = "com.foo.bar";
private final static String CLASS_NAME = PACKAGE_NAME + ".fake_a11y_service"; private static final String CLASS_NAME = PACKAGE_NAME + ".fake_a11y_service";
private final static String COMPONENT_NAME = PACKAGE_NAME + "/" + CLASS_NAME; private static final String COMPONENT_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
private Context mContext; private Context mContext;
private AccessibilityDetailsSettingsFragment mFragment;
private ShadowAccessibilityManager mShadowAccessibilityManager; private FragmentController<AccessibilityDetailsSettingsFragment> mFragmentController;
@Captor
private ArgumentCaptor<Intent> mIntentArgumentCaptor;
@Mock private FragmentActivity mActivity;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); mContext = ApplicationProvider.getApplicationContext();
mContext = spy(RuntimeEnvironment.application); ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
mFragment = spy(new AccessibilityDetailsSettingsFragment()); AccessibilityManager.getInstance(mContext));
mShadowAccessibilityManager = Shadow.extract(AccessibilityManager.getInstance(mContext)); shadowAccessibilityManager.setInstalledAccessibilityServiceList(getMockServiceList());
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(getMockServiceList());
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mContext).when(mFragment).getContext();
} }
@Test @Test
public void onCreate_afterSuccessfullyLaunch_shouldBeFinished() { public void onCreate_afterSuccessfullyLaunch_shouldBeFinished() {
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
doReturn(intent).when(mActivity).getIntent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
verify(mActivity).finish(); assertThat(fragment.getActivity().isFinishing()).isTrue();
} }
@Test @Test
public void onCreate_hasValidExtraComponentName_launchExpectedFragment() { public void onCreate_hasValidExtraComponentName_launchExpectedFragment() {
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
doReturn(intent).when(mActivity).getIntent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(mActivity, assertStartActivityWithExpectedFragment(fragment.getActivity(),
ToggleAccessibilityServicePreferenceFragment.class.getName()); ToggleAccessibilityServicePreferenceFragment.class.getName());
} }
@Test @Test
public void onCreate_hasInvalidExtraComponentName_launchAccessibilitySettings() { public void onCreate_hasInvalidExtraComponentName_launchAccessibilitySettings() {
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, PACKAGE_NAME + "/.service"); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, PACKAGE_NAME + "/.service");
doReturn(intent).when(mActivity).getIntent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(mActivity, AccessibilitySettings.class.getName()); assertStartActivityWithExpectedFragment(fragment.getActivity(),
AccessibilitySettings.class.getName());
} }
@Test @Test
public void onCreate_hasNoExtraComponentName_launchAccessibilitySettings() { public void onCreate_hasNoExtraComponentName_launchAccessibilitySettings() {
final Intent intent = new Intent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
doReturn(intent).when(mActivity).getIntent(); new Intent());
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(mActivity, AccessibilitySettings.class.getName()); assertStartActivityWithExpectedFragment(fragment.getActivity(),
AccessibilitySettings.class.getName());
} }
@Test @Test
public void onCreate_extraComponentNameIsDisallowed_launchAccessibilitySettings() { public void onCreate_extraComponentNameIsDisallowed_launchAccessibilitySettings() {
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
doReturn(intent).when(mActivity).getIntent(); DevicePolicyManager dpm = mContext.getSystemService(
doReturn(false).when(mFragment).isServiceAllowed(anyInt(), any()); DevicePolicyManager.class);
((ShadowDevicePolicyManager) Shadows.shadowOf(dpm)).setPermittedAccessibilityServices(
ImmutableList.of());
mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(mActivity, AccessibilitySettings.class.getName()); assertStartActivityWithExpectedFragment(fragment.getActivity(),
AccessibilitySettings.class.getName());
} }
@Test @Test
public void onCreate_magnificationComponentName_launchMagnificationFragment() { public void onCreate_magnificationComponentName_launchMagnificationFragment() {
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
MAGNIFICATION_COMPONENT_NAME.flattenToString()); MAGNIFICATION_COMPONENT_NAME.flattenToString());
doReturn(intent).when(mActivity).getIntent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(fragment.getActivity(),
assertStartActivityWithExpectedFragment(mActivity,
ToggleScreenMagnificationPreferenceFragment.class.getName()); ToggleScreenMagnificationPreferenceFragment.class.getName());
} }
@Test @Test
public void onCreate_accessibilityButton_launchAccessibilityButtonFragment() { public void onCreate_accessibilityButton_launchAccessibilityButtonFragment() {
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToString()); ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToString());
doReturn(intent).when(mActivity).getIntent(); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
mFragment.onCreate(Bundle.EMPTY); AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(mActivity, assertStartActivityWithExpectedFragment(fragment.getActivity(),
AccessibilityButtonFragment.class.getName()); AccessibilityButtonFragment.class.getName());
} }
@@ -177,20 +175,25 @@ public class AccessibilityDetailsSettingsFragmentTest {
public void onCreate_hearingAidsComponentName_launchAccessibilityHearingAidsFragment() { public void onCreate_hearingAidsComponentName_launchAccessibilityHearingAidsFragment() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, true); FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, true);
final Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()); ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
doReturn(intent).when(mActivity).getIntent();
mFragment.onCreate(Bundle.EMPTY); mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
intent);
assertStartActivityWithExpectedFragment(mActivity, AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertStartActivityWithExpectedFragment(fragment.getActivity(),
AccessibilityHearingAidsFragment.class.getName()); AccessibilityHearingAidsFragment.class.getName());
} }
@Test @Test
public void getMetricsCategory_returnsCorrectCategory() { public void getMetricsCategory_returnsCorrectCategory() {
assertThat(mFragment.getMetricsCategory()).isEqualTo( mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment());
AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
assertThat(fragment.getMetricsCategory()).isEqualTo(
SettingsEnums.ACCESSIBILITY_DETAILS_SETTINGS); SettingsEnums.ACCESSIBILITY_DETAILS_SETTINGS);
} }
@@ -224,10 +227,9 @@ public class AccessibilityDetailsSettingsFragmentTest {
return infoList; return infoList;
} }
private void assertStartActivityWithExpectedFragment(Context mockContext, String fragmentName) { private void assertStartActivityWithExpectedFragment(Activity activity, String fragmentName) {
verify(mockContext).startActivity(mIntentArgumentCaptor.capture()); Intent intent = Shadows.shadowOf(activity).getNextStartedActivity();
assertThat(mIntentArgumentCaptor.getValue() assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) fragmentName);
.isEqualTo(fragmentName);
} }
} }

View File

@@ -19,6 +19,7 @@ import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -36,6 +37,8 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
private int mPasswordMinLength = 0; private int mPasswordMinLength = 0;
private int mPasswordMinSymbols = 0; private int mPasswordMinSymbols = 0;
private List<String> mPermittedAccessibilityServices = null;
public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) { public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
mSupportMessagesMap.put(Objects.hash(admin, userHandle), message); mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
} }
@@ -122,6 +125,16 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
mPasswordMinSymbols = numOfSymbols; mPasswordMinSymbols = numOfSymbols;
} }
public void setPermittedAccessibilityServices(List<String> permittedAccessibilityServices) {
mPermittedAccessibilityServices = permittedAccessibilityServices;
}
@Implementation
@Nullable
public List<String> getPermittedAccessibilityServices(int userId) {
return mPermittedAccessibilityServices;
}
public static ShadowDevicePolicyManager getShadow() { public static ShadowDevicePolicyManager getShadow() {
return (ShadowDevicePolicyManager) Shadow.extract( return (ShadowDevicePolicyManager) Shadow.extract(
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class)); RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));