1

I have a custom progress dialog with a progressbar and a message displayed during network calls.(For e.g. Logging in..., Fetching data etc., ).

I want to write a test to verify the dialogfragment with given text is displayed or not.

CustomProgressDialog.java

public class CustomProgressDialog extends DialogFragment {

  private static final String KEY_MESSAGE = "message";
  public static final String TAG_PROGRESS_DIALOG = "progress_dialog";

  @BindView(R.id.progressbar) ProgressBar mProgressBar;
  @BindView(R.id.progress_textview) TextView mProgressTextView;

  private Unbinder mUnbinder;

  public static CustomProgressDialog start(String progressMessage) {
    CustomProgressDialog dialog = new CustomProgressDialog();

    Bundle bundle = new Bundle();
    bundle.putString(KEY_MESSAGE, progressMessage);
    dialog.setArguments(bundle);
    return dialog;
  }

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    setCancelable(false);
  }

  @Override public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = getActivity().getLayoutInflater();

    Bundle bundle = getArguments();
    String mProgressMessage;
    if (bundle != null && bundle.containsKey(KEY_MESSAGE)) {
      mProgressMessage = bundle.getString(KEY_MESSAGE);
    } else {
      mProgressMessage = getActivity().getString(R.string.progress_loading);
    }

    View view = inflater.inflate(R.layout.dialog_custom_progress, null);
    mUnbinder = ButterKnife.bind(this, view);
    mProgressTextView.setText(mProgressMessage);

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setView(view);

    return builder.create();
  }


  /**
   * Helper method to show a progress dialog with a message.
   */
  public static void showDialog(FragmentActivity activity, String message) {
    showDialog(activity, message, TAG_PROGRESS_DIALOG);
  }

  /**
   * Helper method to show a progress dialog with a message.
   */
  public static void showDialog(FragmentActivity activity, String message, String tag) {
    CustomProgressDialog progressDialog = CustomProgressDialog.start(message);
    progressDialog.show(activity.getSupportFragmentManager(), tag);
  }

  public static void hideDialog(FragmentActivity activity) {
    hideDialog(activity, TAG_PROGRESS_DIALOG);
  }

  /**
   * Helper method to hide a progress dialog.
   */
  public static void hideDialog(FragmentActivity activity, String tag) {
    FragmentManager fragmentManager = activity.getSupportFragmentManager();
    DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(tag);
    if (dialogFragment != null) {
      Timber.d("Gonna dismiss the dialog.");
      dialogFragment.dismiss();
    }
  }

  @Override public void onDestroyView() {
    if (getDialog() != null && getRetainInstance()) {
      getDialog().setDismissMessage(null);
      mUnbinder.unbind();
    }
    super.onDestroyView();
  }
}

dialog_custom_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:layout_marginTop="@dimen/spacing_small"
    android:layout_marginBottom="@dimen/spacing_small"
    android:padding="@dimen/spacing_xlarge"
    >

  <ProgressBar
      android:id="@+id/progressbar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_centerVertical="true"
      android:indeterminate="true"
      android:indeterminateTint="@color/primary_dark"
      android:indeterminateTintMode="src_in"
      />

  <TextView
      android:id="@+id/progress_textview"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_centerVertical="true"
      android:gravity="left"
      android:layout_marginLeft="@dimen/spacing_medium"
      android:layout_toRightOf="@+id/progressbar"
      android:maxLines="3"
      tools:text="@string/placeholder_progress_text"
      style="@style/ProgressTextStyle"
      />

</RelativeLayout>

LoginFragment.java

private void doLogin() {
  //blah.. blah ..
  CustomProgressDialog.showDialog(getActivity(),
        getActivity().getString(R.string.progress_logging_in));
}

Sample testcase

 @Test public void checkProgressBar_displayedWhileLoggingIn() throws Exception {
    // GIVEN
    ...... 

    // WHEN
    onView(LOGIN_BUTTON).perform(click());

    // THEN
    // TODO check for progress bar is displayed.
    //onView(withText(R.string.progress_logging_in)).check(matches(isDisplayed()));                
    onView(withId(R.id.progress_textview)).check(matches(isDisplayed()));

  }

I'd got the following error for the above testcase:

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.custom.android.internal.debug:id/progress_textview

Although progress_textview is displayed on the screen.

blizzard
  • 5,275
  • 2
  • 34
  • 48
  • What is the actual problem? Please formulate clear questions. Does it not work? What does not work? Or do you want some advice on how to test dialogs in general or just the progress bar and text? – thaussma Jun 26 '16 at 21:42
  • @Herrmann I have updated the code and the resulting exception, Hope it gives clear picture. – blizzard Jun 27 '16 at 10:20
  • Hmm, I am successfully matching views in dialogs with `onView`. Pls post the complete error log and `R.layout.dialog_custom_progress`. – thaussma Jun 29 '16 at 07:41
  • @Herrmann Updated the post with layout code. – blizzard Jun 29 '16 at 09:16

1 Answers1

0

Espresso doesn't work well when indeterminate progressbar is enabled.

Refer:
1. Testing progress bar on Android with Espresso.
2. ProgressBars and Espresso

Based on the solutions given in the posts and by following the gist, I created two different versions of progressbar for each productFlavor like below:

productFlavor(Debug)/ProgressBar.java

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.animation.Animation;

/**
 * Progressbar that is used in UI Tests
 * Prevents the progressbar from ever showing and animating
 * Thus allowing Espresso to continue with tests and Espresso won't be blocked
 */    
public class ProgressBar extends android.widget.ProgressBar {

  public ProgressBar(Context context) {
    super(context);
    setUpView();
  }

  public ProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    setUpView();
  }

  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    setUpView();
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    setUpView();
  }

  private void setUpView() {
    this.setVisibility(GONE);
  }

  @Override
  public void setVisibility(int v) {
    // Progressbar should never show
    v = GONE;
    super.setVisibility(v);
  }

  @Override
  public void startAnimation(Animation animation) {
    // Do nothing in test cases, to not block ui thread
  }
}

productFlavor(Production)/ProgressBar.java

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;

/**
 * Progressbar that just calls the default implementation of Progressbar
 * Should always be used instead of {@link android.widget.ProgressBar}
 */
public class ProgressBar extends android.widget.ProgressBar {

    public ProgressBar(Context context) {
        super(context);
    }

    public ProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

}

And modified the layout dialog_custom_progress.xml progressbar with:

<com.projectname.android.custom.ProgressBar
      android:id="@+id/progressbar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_centerVertical="true"
      android:indeterminate="true"
      android:indeterminateTint="@color/primary_dark"
      android:indeterminateTintMode="src_in"
      />

Finally test case runs successfully.

Community
  • 1
  • 1
blizzard
  • 5,275
  • 2
  • 34
  • 48