使用 Espresso 检查是否显示自定义进度 DialogFragment?
Check if a custom progress DialogFragment is shown or not using Espresso?
我有一个自定义进度对话框,其中包含进度条和在网络调用期间显示的消息。(例如登录...、获取数据等)。
我想编写一个测试来验证带有给定文本的对话片段是否显示。
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));
}
示例测试用例
@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()));
}
上述测试用例出现以下错误:
android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.custom.android.internal.debug:id/progress_textview
虽然屏幕显示progress_textview
启用不确定进度条时,Espresso 效果不佳。
参考:
1. .
2. ProgressBars and Espresso
根据帖子中给出的解决方案并遵循 gist,我为每个 productFlavor 创建了两个不同版本的进度条,如下所示:
productFlavor(调试)/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(生产)/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);
}
}
并修改布局 dialog_custom_progress.xml
进度条:
<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"
/>
终于测试用例运行成功
我有一个自定义进度对话框,其中包含进度条和在网络调用期间显示的消息。(例如登录...、获取数据等)。
我想编写一个测试来验证带有给定文本的对话片段是否显示。
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));
}
示例测试用例
@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()));
}
上述测试用例出现以下错误:
android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.custom.android.internal.debug:id/progress_textview
虽然屏幕显示progress_textview
启用不确定进度条时,Espresso 效果不佳。
参考:
1.
2. ProgressBars and Espresso
根据帖子中给出的解决方案并遵循 gist,我为每个 productFlavor 创建了两个不同版本的进度条,如下所示:
productFlavor(调试)/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(生产)/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);
}
}
并修改布局 dialog_custom_progress.xml
进度条:
<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"
/>
终于测试用例运行成功