为什么 android espresso 测试在检查 textView 文本是否以预期字符串结尾时失败(省略号时)

Why android espresso test fails when checking whether textView text ends with expected string (when ellipsized)

我有一个 android 测试,检查在应用 android:ellipsize="end" 时外部文本消息是否被截断并以三个点结尾。尽管 activity 中显示的文本格式正确,但我不知道为什么测试失败。

@Test
fun when_errorMessage_is_very_long_then_text_of_errorMessageTextView_ends_with_dots() {

    //given
    val errorMessage = """
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long 
    error,"""

    //when
    presentErrorActivityWith(errorMessage)

    //then
    onView(withId(R.id.errorMessageTextView)).check(matches(withText(endsWith("..."))));
}

我使用从

导入的功能
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4

ErrorActivity 布局中的 errorMessageTextView 声明

<TextView
    android:id="@+id/errorMessageTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:ellipsize="end"
    android:maxLines="2"

    android:paddingLeft="24dp"
    android:paddingRight="24dp"

    android:layout_marginTop="8dp"

    android:layout_marginStart="40dp"
    android:layout_marginLeft="40dp"
    android:layout_marginEnd="40dp"
    android:layout_marginRight="40dp"
    app:layout_constraintTop_toBottomOf="@+id/errorMessageTitleTextView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    android:text=""/>

可能是因为您正在检查字符串 "..." 而不是字符串 "…"(后者是一个字符而不是三个点字符)。

通过查看 Espresso 输出仔细检查这一点。 "Got: AppCompatTextView" ..." 有一个 text= 部分可以准确告诉您 Espresso 在视图中找到的文本。

您不能通过检查 android:ellipsize 是否以“...”结尾来测试 TextView

那是因为即使你看到它以“...”结尾,但实际上它并不是以“...”结尾的。

要验证这一点,您可以进行此测试

@Test
fun check_textview_text() {

    //given
    val errorMessage = """
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long error,
            Very long error, Very long error, Very long error, Very long error, Very long 
    error,"""

    //when
    presentErrorActivityWith(errorMessage)

    //then
    onView(withId(R.id.errorMessageTextView)).check(matches(withText(containsString(errorMessage ))));
}

如果您的 TextView 包含与 errorMessage 变量中相同的字符串,则此测试必须通过。尽管您实际上在屏幕上看到了 elipsize 三个点“...”。

因为实际上在后台 android 系统不会将“...”设置为 text 字段的截断字符串的末尾 TextView.

为了测试android:ellipsize正确的方法:

@RunWith(AndroidJUnit4.class)
public class TextViewLongTextWithEllipsizeTest {
    private static final String TAG = "LOG_TAG";

    @Rule
    public ActivityTestRule mActivityRule = new ActivityTestRule<>(
            LongTextActivity.class);

    /**
     * Testing if a TextView uses "android:ellipsize"
     * at the end of its text as the text is long
     */
    @Test
    public void testTextIsEllipsized() {

        TextView textView = mActivityRule.getActivity().findViewById(R.id.errorMessageTextView);

        Layout layout = textView.getLayout();
        if (layout != null) {
            int ellipsisCount = layout.getEllipsisCount(layout.getLineCount() - 1);
            assertThat(ellipsisCount, is(greaterThan(0))); // if true then text is ellipsized
        }
    }

    /**
     * Testing if a TextView doesn't use "android:ellipsize"
     * at the end of its text as the text is not that long
     */
    @Test
    public void testTextNotEllipsized() {

        TextView textView = mActivityRule.getActivity().findViewById(R.id.no_ellipsize_text);

        Layout layout = textView.getLayout();
        if (layout != null) {
            int ellipsisCount = layout.getEllipsisCount(layout.getLineCount() - 1);
            assertThat(ellipsisCount, not(greaterThan(0))); // if true then text is not ellipsized
        }
    }


}

提示:我刚刚添加了测试方法,请复制测试givenwhen 测试前的声明。

要检查 TextView 的文本是否已被省略,您可以像这样创建自定义匹配器:

fun ellipsized() = object : TypeSafeMatcher<View>() {
    override fun describeTo(description: Description) {
        description.appendText("with ellipsized text")
    }

    override fun matchesSafely(v: View): Boolean {
        if (!(v is TextView)) {
            return false
        }
        val textView: TextView = v
        val layout: Layout = textView.getLayout()
        val lines = layout.lineCount
        if (lines > 0) {
            val ellipsisCount = layout.getEllipsisCount(lines - 1)
            if (ellipsisCount > 0) {
                return true
            }
        }

        return false
    }
}

并这样称呼它:

onView(withId(R.id.errorMessageTextView))
    .check(matches(ellipsized()))