如何使用 Android Espresso 测试 TextInputLayout 值(提示、错误等)?
How to test TextInputLayout values (hint, error, etc.) using 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
代码可以很容易地解决这个问题,但我无法让它工作。
有解决此问题的想法吗?
这是我的自定义匹配器:
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
个 TextInputLayout
,请更改此行:
CharSequence error = ((TextInputLayout) view).getHint();
和
CharSequence error = ((TextInputLayout) view).getError();
希望对您有所帮助
适用于任何具有 "getHint" 方法的视图的更通用的解决方案:
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"))));
上述解决方案不适用于我的用例。我想找到 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"))
一个更简单的解决方案是检查错误文本是否可见,例如:
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
}
}
如果您要检查 Material TextInputLayout 中的错误,请尝试这样的操作:
onView(withId(viewId)).check(matches(textInputLayoutErrorTextMatcher(getString(stringId))))
确保提供 TextInputLayout 而不是其子项(即 TextInputEditText)的 ID。
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")))
你有两个解决方案
-第一个
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
}
使用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")
}
}
如果我的 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
代码可以很容易地解决这个问题,但我无法让它工作。
有解决此问题的想法吗?
这是我的自定义匹配器:
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
个 TextInputLayout
,请更改此行:
CharSequence error = ((TextInputLayout) view).getHint();
和
CharSequence error = ((TextInputLayout) view).getError();
希望对您有所帮助
适用于任何具有 "getHint" 方法的视图的更通用的解决方案:
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"))));
上述解决方案不适用于我的用例。我想找到 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"))
一个更简单的解决方案是检查错误文本是否可见,例如:
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
}
}
如果您要检查 Material TextInputLayout 中的错误,请尝试这样的操作:
onView(withId(viewId)).check(matches(textInputLayoutErrorTextMatcher(getString(stringId))))
确保提供 TextInputLayout 而不是其子项(即 TextInputEditText)的 ID。
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")))
你有两个解决方案
-第一个
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
}
使用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")
}
}