0

I want to test change email in my Android app. I use Robolectric 4.3.1.

I have class that loads fragment with preferences.

public class ApplicationPreferencesActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_container);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.container, new SettingsFragment())
                .commit();
    }

}

fragment_container:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".zeus.ApplicationPreferencesActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </FrameLayout>

</LinearLayout>

In SettingsFragment I load EditTextPreference with email.

public class SettingsFragment extends PreferenceFragmentCompat {

    private String TAG = "kb_settings";

    private EditTextPreference locationIntervalPreference;
    private EditTextPreference buildingRadiusPreference;

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.prefs, rootKey);

        EditTextPreference emailPreference = findPreference("email");
        // next onClick and onChange listeners
    }
}

prefs:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/preferences_screen">

    <PreferenceCategory
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:summary="@string/preferences_summary"
        android:title="@string/preferences_button"
        android:id="@+id/preferences_category">

        <EditTextPreference
            android:key="email"
            android:summary="@string/preferences_email_summary"
            android:title="@string/preferences_email_title" />

    </PreferenceCategory>

</PreferenceScreen>

I added class to check, if preference is displayed.

@RunWith(RobolectricTestRunner.class)
public class ChangeEmailTest {

    private Context context;

    @Rule
    public ActivityTestRule<ApplicationPreferencesActivity> settingsRule =
            new ActivityTestRule<>(ApplicationPreferencesActivity.class, true, false);

    @Before
    public void initEnvironment() {
        //...

        settingsRule.launchActivity(new Intent(ApplicationProvider.getApplicationContext(), ApplicationPreferencesActivity.class));
    }

    @Test
    public void testChangeEmail() {
        onData(allOf(
                is(instanceOf(Preference.class)),
                withKey("email"),
                withSummary(R.string.preferences_email_summary),
                withTitle(R.string.preferences_email_title)))
                .check(matches(isCompletelyDisplayed()))
    }

}

Above code generates below exception.

androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: is assignable from class: class android.widget.AdapterView
at java.lang.Thread.getStackTrace(Thread.java:1559)
    at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:96)
    at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
    at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:322)
    at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:178)
    at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:119)
    at androidx.test.espresso.DataInteraction$DisplayDataMatcher$1.apply(DataInteraction.java:213)
    at androidx.test.espresso.DataInteraction$DisplayDataMatcher$1.apply(DataInteraction.java:210)
    at androidx.test.espresso.DataInteraction$DisplayDataMatcher.<init>(DataInteraction.java:230)
    at androidx.test.espresso.DataInteraction$DisplayDataMatcher.<init>(DataInteraction.java:205)
    at androidx.test.espresso.DataInteraction$DisplayDataMatcher.displayDataMatcher(DataInteraction.java:248)
    at androidx.test.espresso.DataInteraction.makeTargetMatcher(DataInteraction.java:150)
    at androidx.test.espresso.DataInteraction.perform(DataInteraction.java:135)
    at com.netteam.zeus.ChangeEmailTest.testChangeEmail(ChangeEmailTest.java:113)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:546)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

I tried to resolve this exception by this and this. I tried all below cases and all fail.

onData(PreferenceMatchers.withKey(context.getString(R.string.email)))
       .check(matches(isDisplayed()));

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

onData(anything())
        .inAdapterView(allOf(
                 isDescendantOfA(withId(R.id.container)),
                 withId(R.id.preferences_category)))
        .atPosition(1)
        .check(matches(isDisplayed()));

onData(allOf(is(instanceOf(Preference.class)), withKey("email")))
        .onChildView(withText(R.string.preferences_email_title))
        .check(matches(isDisplayed()));

onData(anything())
        .atPosition(1)
        .onChildView(withText(R.string.preferences_email_title))
        .check(matches(isDisplayed()));

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

onData(allOf(is(instanceOf(Preference.class)), withKey("email")))
        .check(matches(isDisplayed()));

onData(PreferenceMatchers.withKey("email"))
        .check(matches(isDisplayed()));

How to resolve this problem?

Edit

Workaround for ActivityScenario:

try (ActivityScenario<SettingsActivity> activityScenario =
                     launch(SettingsActivity.class)) {
            activityScenario.onActivity(
                    activity -> {
                        settingsFragment = activity.getSettingsFragment();

                        String NEW_EMAIL = "new.email@doamin.pl";
                        EditTextPreference emailPreference = settingsFragment.getEmailPreference();
                        emailPreference.performClick();
                        emailPreference.callChangeListener(NEW_EMAIL);

                        assertThat("Check, if new e-mail is saved.",
                                Preferences.getString(EMAIL_KEY), is(NEW_EMAIL));
                    });
        }
ali
  • 49
  • 1
  • 7

0 Answers0