Testing Android PreferenceFragment with Espresso

故事扮演 提交于 2019-12-19 21:49:14

问题


I am trying to write tests for the PreferenceFragments fragment in Settings.

However, I've been getting this error: android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: is assignable from class: class android.widget.AdapterView

The code for the Test is the following:

@RunWith(AndroidJUnit4.class)
@SmallTest
public class SettingsFragmentTest {

    @Rule
    public ActivityTestRule<SettingsActivity> mActivityRule = new ActivityTestRule<>(
            SettingsActivity.class);

    @Test
    public void preferredLocationShouldBeVisibleOnDisplay(){
        mActivityRule.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                SettingsFragment settingsFragment = startSettingsFragment();
            }
        });

        // This check passes correctly
        onView(withId(R.id.weather_settings_fragment))
                .check(matches(isCompletelyDisplayed()));

        // This check gives me the NoMatchingViewException
        onData(allOf(is(instanceOf(Preference.class)),
                withKey("location")))
                .check(matches(isCompletelyDisplayed()));
    }

    private SettingsFragment startSettingsFragment(){
        SettingsActivity activity = mActivityRule.getActivity();
        FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
        SettingsFragment settingsFragment = new SettingsFragment();

        transaction.replace(R.id.weather_settings_fragment, settingsFragment, "settingsFragment");
        transaction.commit();

        return settingsFragment;
    }
}

The settings_activity layout looks as follows:

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          android:name="com.example.android.sunshine.SettingsFragment"
          android:id="@+id/weather_settings_fragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />

And the Preferences Screen layout is the following:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">

    <EditTextPreference
        android:defaultValue="@string/pref_location_default"
        android:inputType="text"
        android:key="@string/pref_location_key"
        android:singleLine="true"
        android:title="@string/pref_location_label" />

    <ListPreference
        android:defaultValue="@string/pref_units_metric"
        android:entries="@array/pref_units_options"
        android:entryValues="@array/pref_units_values"
        android:key="@string/pref_units_key"
    android:title="@string/pref_units_label" />

<CheckBoxPreference
    android:defaultValue="@bool/show_notifications_by_default"
    android:key="@string/pref_enable_notifications_key"
    android:summaryOff="@string/pref_enable_notifications_false"
    android:summaryOn="@string/pref_enable_notifications_true"
    android:title="@string/pref_enable_notifications_label" />

</PreferenceScreen>

I haven't been able to find any examples or information online on how to test PreferenceFragments. Most of the information related to testing Activities.


回答1:


PreferenceMatchers seems to work only with the preference classes from the Android framework, but not with support preference library (com.android.support:preference-v14). Since the latter uses a RecylerView internally, I was able to get hold of the preference items by using RecyclerViewActions from espresso-contrib:

onView(withId(R.id.list))
       .perform(RecyclerViewActions.actionOnItem(hasDescendant(withText(R.string.pref_manage_categories_title)),
            click()));



回答2:


You can use onData() with allOf() and withTitle():

onData(allOf(is(
        instanceOf(Preference.class)),
        withTitle(R.string.my_pref_string)))
        .perform(click());

Or use onData() with allOf() and withKey():

onData(allOf(is(instanceOf(Preference.class)), withKey("myPrefKey")))
        .onChildView(withText(R.string.my_pref_string))
        .perform(click());

Or use onData() with anything(), but this can be unreliable and cause timeouts:

// atPosition() is required - Not sure why
onData(anything())
        .atPosition(3)
        .onChildView(withText(R.string.my_pref_string))
        .perform(click());

Asserting or checking for a preference item is done in a similar way:

onData(allOf(is(
        instanceOf(Preference.class)),
        withTitle(R.string.my_pref_string)))
        .check(matches(isDisplayed()));

Note: To add quickly add the imports for these methods, put the blinking cursor on the unresolved method, then do Android Studio ➔ Help ➔ Find Action ➔ search for "show intention action" ➔ click on the result option ➔ A popup window will appear ➔ click on "Import static method ...". You can also assign a keyboard shortcut to "Show Intention Actions". More info here. Another way is to enable "Add unambiguous imports on the fly" in the Settings.




回答3:


I normally test Fragments through their activity with Espresso. Just test the UI exposed by your Fragment as if it were in the Activity that you're starting with the ActivityTestRule. If the Fragment isn't present on initial launch of the Activity, navigate in your test the same way a user would in order to start the Fragment transaction. If you find yourself needing to test business logic that requires you to stand up Fragments in some sort of test harness, that's usually a good indicator that it should be pulled out into a separate class that can be (ideally) unit tested devoid of any Android dependencies.




回答4:


You can always try Record Espresso test https://developer.android.com/studio/test/espresso-test-recorder.html

Here is the tips on how to work with lists https://developer.android.com/training/testing/espresso/lists.html

This is PreferenceMatcher that expose API like this:

    onData(PreferenceMatchers.withKey(mContext.getString(R.string.key_settings)))
         .perform(click());



回答5:


@Test
    public void clickListPreference() throws Exception{

        // Check if it is displayed
        Context appContext = InstrumentationRegistry.getTargetContext();

        onData(allOf(
           is(instanceOf(Preference.class)),
           withKey(appContext.getResources().getString(R.string.pref_units_key))))
          .check(matches(isDisplayed()));

        // Check if click is working
        onData(allOf(
           is(instanceOf(Preference.class)),
           withKey(appContext.getResources().getString(R.string.pref_units_key))))           
          .onChildView(withText(appContext.getResources()
              .getString(R.string.pref_units_label))).perform(click());
 }

Hope this will help you..



来源:https://stackoverflow.com/questions/45172505/testing-android-preferencefragment-with-espresso

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!