将浓缩咖啡与自定义 EditText 结合使用

Use espresso with custom EditText

这是我的部分布局:

<com.rey.material.widget.EditText
            android:id="@+id/tagEditorSettings"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_marginStart="10dp"
            android:layout_toEndOf="@+id/circularProgressbar"
            android:hint="@string/tag_name_tag_settings"
            android:inputType="text"
            android:textSize="18sp"
            app:et_dividerColor="@color/my_primary"
            app:et_dividerHeight="1dp"
            app:et_inputId="@+id/name_input"
            app:et_labelEnable="true"
            app:et_labelTextSize="14sp"
            app:et_supportLines="1" />

和我的测试代码:

onView(withId(R.id.tagEditorSettings))
                .perform(click()).perform(clearText());

当我尝试 运行 时,我得到这样的错误:

Caused by: java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints: (is displayed on the screen to the user and is assignable from class: class android.widget.EditText)

据我所知,问题出在 "is assignable from class: class android.widget.EditText",但有人可以提供建议,我该如何修复它并在我的案例中使用?

问题com.rey.material.widget.EditText is extended from Framelayout and clearText uses ReplaceTextAction作为

  public static ViewAction clearText() {
      return actionWithAssertions(new ReplaceTextAction(""));
  }

其中 ReplaceTextAction 强制执行 view,一种 EditText 作为

allOf(isDisplayed(), isAssignableFrom(EditText.class));
//                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

因为 rey...EdiText 不是 EditText 的子类,所以错误


解决方案 : 创建你自己的 ViewAction 作为

public static ViewAction clearTextInCustomView(){
            return new ViewAction() {
                @SuppressWarnings("unchecked")
                @Override
                public Matcher<View> getConstraints() {
                    return allOf(isDisplayed(), isAssignableFrom(com.rey.material.widget.EditText.class));
//                                            ^^^^^^^^^^^^^^^^^^^ 
// To check that the found view is type of com.rey.material.widget.EditText or it's subclass
                }

                @Override
                public void perform(UiController uiController, View view) {
                    ((com.rey.material.widget.EditText) view).setText("");
                }

                @Override
                public String getDescription() {
                    return "clear text";
                }
            };
    }

稍后你可以做

onView(withId(R.id.tagEditorSettings))
                .perform(click()).perform(clearTextInCustomView());

此自定义 EditText 扩展自 FrameLayout。这就是为什么它抱怨无法从 class android.widget.EditText.

分配目标

但是,这个自定义的 EditText 有一些方法,比如 setText 来设置包含的 EditText 中的文本,定义为:

protected android.widget.EditText mInputView;

这个是 android.widget 包中的 EditText。

您可以创建自定义 ViewAction 来访问此 public 方法:

public static ViewAction setTextEditText(final Matcher<View> matcher,
   final String newText) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return allOf(isDisplayed(), isAssignableFrom(com.rey.material.widget.EditText.class));
        }

        @Override
        public String getDescription() {
            return "Update the text from the custom EditText";
        }

        @Override
        public void perform(final UiController uiController, final View view) {
            ((com.rey.material.widget.EditText) view).setText(newText);
        }
    };
}

然后,您可以执行自定义ViewAction:

onView(withId(R.id.tagEditorSettings)).setTextEditText(null);

对于 kotlin 解决方案:

fun setTextEditText(
    newText: String?
): ViewAction {
    return object : ViewAction {

        override fun getConstraints(): Matcher<View> {
            return CoreMatchers.allOf(
                ViewMatchers.isDisplayed(),
                ViewMatchers.isAssignableFrom(CustomDefaultInput::class.java)
            )
        }

        override fun getDescription(): String {
            return "Update the text from the custom EditText"
        }

        override fun perform(uiController: UiController?, view: View) {
            (view as CustomDefaultInput).textInputEditText.setText(newText)
        }
    }
}

然后你 运行 与 :

onView(withId(R.id.inputCityName)).perform(setTextEditText(newText = "Ab"))