0

I am trying to test MyActivity shows an alert dialog when incorrect intent extras were passed. It is a url, so I pass the url to a internal webView to load the url and show an alert if any error happened. The alert should be dismissed when the positive button is clicked.

This is how the alertDialog is created when the error happens

// Method in `MyActivity.java` called when the url couldn't be loaded
private void showAlertDialog(final String title, final String message) {

    final MyActivity self = this;
    runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (!isFinishing()) {

                    alertDialog = new AlertDialog.Builder(MyActivity.this)
                        .setTitle(title)
                        .setMessage(message)
                        .setCancelable(false)
                        .setPositiveButton(BUTTON_OK_TITLE, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                self.alertDialog = null;
                                //self.finishWithMessage(messageRaw, true);
                            }
                        }).create();
                   alertDialog.show();
                }
            }
    });
}

In the test, I am using ElapsedTimeIdlingResource taken from chiuki's answer to wait 10 seconds after launching the activity and assert the alertDialog was created and showing.

Then I am pressing the alert button and wait again 10 seconds to try to assert it is gone.

This is the test code MyActivityTest.java:

@RunWith(AndroidJUnit4.class)
public class MyActivityTest {

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

@Test
public void testErrorDialog() {
    Intent intent = createIntentWithWrongExtras();
    mActivityRule.launchActivity(intent);

    // Wait
    IdlingResource idlingResource1 = new ElapsedTimeIdlingResource(10000);
    Espresso.registerIdlingResources(idlingResource1);

    assertNotNull("Activity should have been created", mActivityRule.getActivity());
    assertNotNull("AlertDialog should have been created", mActivityRule.getActivity().alertDialog);
    assertTrue("AlertDialog should be showing", mActivityRule.getActivity().alertDialog.isShowing());

    // Test clicking the button dismisses the alert
    mActivityRule.getActivity().runOnUiThread(() ->
            mActivityRule.getActivity().alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
    );

    IdlingResource idlingResource2 = new ElapsedTimeIdlingResource(10000);
    Espresso.registerIdlingResources(idlingResource2);

    assertTrue("AlertDialog should NOT be showing", mActivityRule.getActivity().alertDialog == null || !mActivityRule.getActivity().alertDialog.isShowing());

    Espresso.unregisterIdlingResources(idlingResource2);
}

}

However the test always fails:

"AlertDialog should NOT be showing"

I don't think I am understanding well what is really going on. I wrote some logs and I can see that idlingResource1 never waits for 10 seconds. Also I know alertDialog becomes null when dismissed but that happens after the last assert, so idlingResource2 is not working either? Why? Is this the right way to test this?

Community
  • 1
  • 1
nacho4d
  • 43,720
  • 45
  • 157
  • 240

2 Answers2

2

IdlingResources make Espresso wait. But you do not use Espresso to test (besides registering IdlingResources that have no effect), so the test runs straight though without waiting and your test fails.

If you replace your IdlingResources with simple Thread.sleep() your test should work. At least it would wait.

Read a little bit about Espresso, it's easy and would really improve your test: https://developer.android.com/training/testing/ui-testing/espresso-testing.html

thaussma
  • 9,756
  • 5
  • 44
  • 46
1

I don't think you are using Espresso in the right way.

Try remove the idlingResources, and replace the first three assertion with something like:

onView(use_matcher_to_match_the_dialog).check(matches(isDisplayed()));

Espresso will wait until UI thread to become idle.

Then, do the click in Espresso way:

onView(use_matcher_to_match_the_button).perform(click());

and the final assertion:

onView(use_matcher_to_match_the_dialog).check(matches(not(isDisplayed())));
nacho4d
  • 43,720
  • 45
  • 157
  • 240
phq
  • 976
  • 1
  • 6
  • 3