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

时间:2016-08-09 04:24:06

标签: android android-layout android-studio 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次观看,不包含在TextInputLayout中。然而,当它缠绕时,它就不再有效了。

我尝试使用来自Android Espresso - How to check EditText hint?的解决方案,但它仍无效。

我还调查了https://code.google.com/p/android/issues/detail?id=191261报告了这个问题,它说通过指向当前的withHint代码可以很容易地解决这个问题,但我无法让它工作。

有任何解决此问题的想法吗?

10 个答案:

答案 0 :(得分:32)

这是我的自定义匹配器:

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) {
            }
        };
    }
}

以及如何使用:

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Rule
    public ActivityTestRule<MainActivity> mRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void testMyApp() {
        onView(withId(R.id.textInputLayout)).check
                (matches(hasTextInputLayoutErrorText(mRule.getActivity().getString(R.string
                        .app_name))));

    }

如果您想查看errorText的{​​{1}},请更改此行:

TextInputLayout

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

希望它会有所帮助

答案 1 :(得分:1)

更适用于任何具有“getHint”方法的View的通用解决方案:

public static Matcher<View> withCustomHint(final Matcher<String> stringMatcher) {
    return new BaseMatcher<View>() {
        @Override
        public void describeTo(Description description) {
        }

        @Override
        public boolean matches(Object item) {
            try {
                Method method = item.getClass().getMethod("getHint");
                return stringMatcher.matches(method.invoke(item));
            } catch (NoSuchMethodException e) {
            } catch (InvocationTargetException e) {
            } catch (IllegalAccessException e) {
            }
            return false;
        }
    };
}

用法:

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

答案 2 :(得分:1)

kotlin版本的piotrek1543的答案:

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
    }
}

答案 3 :(得分:1)

如果您要检查Material TextInputLayout中的错误,请尝试如下操作:

onView(withId(viewId)).check(matches(textInputLayoutErrorTextMatcher(getString(stringId))))

请确保提供TextInputLayout的ID,而不要提供其子级(即TextInputEditText)。

答案 4 :(得分:1)

某些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
}

答案 5 :(得分:0)

上述解决方案对我的用例不起作用。我想找到TextInputEditText并在其中键入文本。这是我的解决方案:

    @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))
}

用法:

onView(withTextInputHint(R.string.hint)).perform(ViewActions.typeText("Type text here"))

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

可以避免Java反射。此外,TextView及其所有后代(包括TextInputEditText)或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(withId(R.id.exampleView)).check(matches(withHint("example text")))

答案 8 :(得分:0)

您必须解决

-第一

    onView(withText(errorMessage)).check(matches(isDisplayed()))

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

答案 9 :(得分:0)

使用import sys import threading import pafy from time import sleep from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit from PyQt5.QtGui import QIcon from PyQt5.QtCore import pyqtSlot class App(QWidget): threads = [] def __init__(self): super().__init__() self.title = 'YouDio' self.left = 100 self.top = 100 self.width = 280 self.height = 90 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) button = QPushButton('DOWNLOAD', self) button.move(10,25) button.clicked.connect(self.on_click) self.line = QLineEdit(self) self.line.move(120,27) self.show() def on_click(self): self.t = threading.Thread(target=self.threaded) self.t.start() def threaded(self): url = self.line.text() video = pafy.new(url) bestaudio = video.getbestaudio() bestaudio.download() if __name__ == '__main__': app = QApplication([]) ex = App() sys.exit(app.exec_()) 可以摆脱类型检查:

BoundedMatcher