如何使用Android Espresso测试TextInputLayout值(提示、错误等)?

如何使用Android Espresso测试TextInputLayout值(提示、错误等)?,android,android-layout,android-espresso,Android,Android Layout,Android Espresso,如果我的TextInputLayout视图有特定提示,我将尝试使用Espresso进行测试。我使用的代码如下: Espresso.onView(ViewMatchers.withId(R.id.edit_text_email)) .check(ViewAssertions.matches( ViewMatchers.withHint(R.string.edit_text_email_hint))) 这适用于正常的EditText视图,而不是包装在TextInputLay

如果我的
TextInputLayout
视图有特定提示,我将尝试使用Espresso进行测试。我使用的代码如下:

Espresso.onView(ViewMatchers.withId(R.id.edit_text_email))
    .check(ViewAssertions.matches(
        ViewMatchers.withHint(R.string.edit_text_email_hint)))
这适用于正常的
EditText
视图,而不是包装在
TextInputLayout
中。然而,当它环绕时,它就不再工作了

我试图使用来自的解决方案,但仍然不起作用

我还调查了:报告了这个问题,它说通过使用提示指向当前的
代码,解决方法非常简单,但我无法让它工作


有什么办法解决这个问题吗?

这是我的自定义匹配器:

public static Matcher<View> hasTextInputLayoutHintText(final String expectedErrorText) {
        return new TypeSafeMatcher<View>() {

            @Override
            public boolean matchesSafely(View view) {
                if (!(view instanceof TextInputLayout)) {
                    return false;
                }

                CharSequence error = ((TextInputLayout) view).getHint();

                if (error == null) {
                    return false;
                }

                String hint = error.toString();

                return expectedErrorText.equals(hint);
            }

            @Override
            public void describeTo(Description description) {
            }
        };
    }
}


希望它能帮助

更通用的解决方案,该解决方案适用于任何具有“getHint”方法的视图:


上述解决方案不适用于我的用例。我想找到文本InputItemText并在其中键入文本。以下是我的解决方案:

    @VisibleForTesting
class WithTextInputLayoutHintMatcher @RemoteMsgConstructor
constructor(@field:RemoteMsgField(order = 0)
            private val stringMatcher: Matcher<String>) : TypeSafeMatcher<View>() {

    override fun describeTo(description: Description) {
        description.appendText("with TextInputLayout hint: ")
        stringMatcher.describeTo(description)
    }

    public override fun matchesSafely(textInputEditText: View): Boolean {
        if (textInputEditText !is TextInputEditText) return false

        return stringMatcher.matches((textInputEditText.parent.parent as? TextInputLayout)?.hint)
    }
}

/**
 * Returns a matcher that matches [TextInputEditText] based on it's hint property value.
 *
 *
 * **Note:** View's sugar for `withHint(is("string"))`.
 *
 * @param hintText [String] with the hint text to match
 */
fun withTextInputHint(hintText: String): Matcher<View> {
    return withTextInputHint(Matchers.`is`(checkNotNull(hintText)))
}

/**
 * Returns a matcher that matches a descendant of [TextInputEditText] that is displaying the hint
 * associated with the given resource id.
 *
 * @param resourceId the string resource the text view is expected to have as a hint.
 */
fun withTextInputHint(resourceId: Int): Matcher<View> {
    return withTextInputHint(getString(resourceId))
}

/**
 * Returns a matcher that matches [TextView]s based on hint property value.
 *
 *
 * **Note:** View's hint property can be `null`, to match against it use `
 * withHint(nullValue(String.class)`
 *
 * @param stringMatcher [`Matcher
`](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html) *  of [String] with text to match
 */
fun withTextInputHint(stringMatcher: Matcher<String>): Matcher<View> {
    return WithTextInputLayoutHintMatcher(checkNotNull(stringMatcher))
}
@VisibleForTesting
使用TextInputLayoutAuthIntMatcher@RemoteMsgConstructor初始化
构造函数(@field:RemoteMsgField(order=0)
private val stringMatcher:Matcher):TypeSafeMatcher(){
覆盖乐趣描述(描述:描述){
description.appendText(“带有TextInputLayout提示:”)
stringMatcher.Descripto(描述)
}
public override fun matchessesafely(textinputtext:View):布尔值{
如果(textInputItemText!是textInputItemText)返回false
返回stringMatcher.matches((textInputItemText.parent.parent作为?TextInputLayout)?.hint)
}
}
/**
*返回一个匹配器,该匹配器根据[TextInputItemText]的提示属性值匹配[TextInputItemText]。
*
*
***注意:**视图中的sugar表示`withHint(is(“string”)`)。
*
*@param hintText[String]与要匹配的提示文本
*/
有趣的文本输入(hintText:String):匹配器{
返回时使用textinputhint(Matchers.`is`(checkNotNull(hintText)))
}
/**
*返回一个匹配器,该匹配器匹配显示提示的[TextInputInputText]的子代
*与给定的资源id关联。
*
*@param resourceId文本视图应具有的字符串资源作为提示。
*/
textinputhint(resourceId:Int)的乐趣:匹配器{
返回时使用TextInput(getString(resourceId))
}
/**
*返回基于提示属性值与[TextView]匹配的匹配器。
*
*
***注意:**视图的提示属性可以为'null',以便与之匹配`
*withHint(空值(String.class)`
*
*@param stringMatcher[`Matcher
`](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html)*包含要匹配的文本的[字符串]
*/
文本输入权限的乐趣(stringMatcher:Matcher):Matcher{
使用TextInputLayoutAuthIntMatcher(checkNotNull(stringMatcher))返回
}
用法:

onView(withId(R.id.SomeLayout)).check(matches(withCustomHint(is("SomeString"))));

onView(withTextInputHint(R.string.hint))。执行(ViewActions.typeText(“此处键入文本”))

更简单的解决方案是检查错误文本是否可见,例如:

val text = mTestRule.getActivity().getString(R.string.error_text)
onView(withText(text)).check(matches(isDisplayed()))

piotrek1543答案的Kotlin版本:

fun hasTextInputLayoutHintText(expectedErrorText: String): Matcher<View> = object : TypeSafeMatcher<View>() {

    override fun describeTo(description: Description?) { }

    override fun matchesSafely(item: View?): Boolean {
        if (item !is TextInputLayout) return false
        val error = item.hint ?: return false
        val hint = error.toString()
        return expectedErrorText == hint
    }
}
fun HastextInputLayoutIntText(expectedErrorText:String):Matcher=object:TypeSafeMatcher(){
重写fun Descripto(描述:描述?{}
覆盖趣味匹配安全(项目:视图?):布尔值{
如果(item!为TextInputLayout)返回false
val error=item.hint?:返回false
val hint=error.toString()
返回expectedErrorText==提示
}
}

如果要检查材质TextInputLayout中的错误,请尝试以下操作:

onView(withId(R.id.exampleView)).check(matches(withHint("example text")))
onView(带id(viewId)).check(匹配(textInputLayoutErrorTextMatcher(getString(stringId)))


确保提供TextInputLayout的id,而不是其子项(即TextInputItemText)。

可以避免Java反射。此外,TextView及其所有子体(包括TextInputItemText)或TextInputLayout都支持提示。因此

fun withHint(expected: String) = object : TypeSafeMatcher<View>() {
    override fun describeTo(description: Description) {
        description.appendText("TextView or TextInputLayout with hint '$expected'")
    }

    override fun matchesSafely(item: View?) =
        item is TextInputLayout && expected == item.hint || item is TextView && expected == item.hint
}
你有两个解决方案

-首先

    onView(withText(errorMessage)).check(matches(isDisplayed()))
-第二

    onView(withId(R.id.textinput_error)).check(matches(withText(errorMessage)))

有些adobe解决方案是正确的,但我想添加一个kotlin版本,我认为它比其他版本更简单:

fun hasNoErrorText() = object : TypeSafeMatcher<View>() {
    override fun describeTo(description: Description) {
        description.appendText("has no error text ")
    }

    override fun matchesSafely(view: View?) = view is TextInputLayout && view.error == null
}
fun hasnorerrortext()=对象:TypeSafeMatcher(){
覆盖乐趣描述(描述:描述){
description.appendText(“没有错误文本”)
}
override fun matchesSafely(视图:视图?)=视图为TextInputLayout&&view.error==null
}

使用
BoundedMatcher
可以取消类型检查:

fun withHint(@StringRes hintId: Int?) =
    object : BoundedMatcher<View, TextInputLayout>(TextInputLayout::class.java) {

        override fun matchesSafely(item: TextInputLayout?): Boolean =
            when {
                item == null -> false
                hintId == null -> item.hint == null
                else -> item.hint?.toString() == item.context.getString(hintId)
            }

        override fun describeTo(description: Description?) {
            description?.appendText("with hint id $hintId")
        }
    }
funwithhint(@StringRes-hintId:Int?)=
对象:BoundedMatcher(TextInputLayout::class.java){
覆盖有趣的匹配消息(项目:TextInputLayout?):布尔值=
什么时候{
项==null->false
hintId==null->item.hint==null
else->item.hint?.toString()==item.context.getString(hintId)
}
覆盖乐趣描述(描述:描述?){
说明?.appendText(“带有提示id$hintId”)
}
}

我可以将自定义匹配器HastextInputLayoutIntText放在哪里?因为在我的代码中我将错误设置为TextInputItemText,所以我必须在匹配器中将TextInputLayout更改为TextInputItemText。如果您继承自
    onView(withText(errorMessage)).check(matches(isDisplayed()))
    onView(withId(R.id.textinput_error)).check(matches(withText(errorMessage)))
fun hasNoErrorText() = object : TypeSafeMatcher<View>() {
    override fun describeTo(description: Description) {
        description.appendText("has no error text ")
    }

    override fun matchesSafely(view: View?) = view is TextInputLayout && view.error == null
}
fun withHint(@StringRes hintId: Int?) =
    object : BoundedMatcher<View, TextInputLayout>(TextInputLayout::class.java) {

        override fun matchesSafely(item: TextInputLayout?): Boolean =
            when {
                item == null -> false
                hintId == null -> item.hint == null
                else -> item.hint?.toString() == item.context.getString(hintId)
            }

        override fun describeTo(description: Description?) {
            description?.appendText("with hint id $hintId")
        }
    }