我正在为我的基于 Espresso 的 Android 应用程序编写一些测试。单击 TextView 内的链接(使用 Linkify 类创建)后,我需要断言我看到的是正确的屏幕。
我尝试单击包含链接的 TextView,但链接不会打开。
是否有使用 Espresso 进行测试的正确方法(除了修改代码以使链接具有单独的 TextView)?
我正在为我的基于 Espresso 的 Android 应用程序编写一些测试。单击 TextView 内的链接(使用 Linkify 类创建)后,我需要断言我看到的是正确的屏幕。
我尝试单击包含链接的 TextView,但链接不会打开。
是否有使用 Espresso 进行测试的正确方法(除了修改代码以使链接具有单独的 TextView)?
我发现了一种更简单的方法,在ViewActions中有一个名为openLinkWithText的方法,它使用 linkTextMatcher 作为匹配器来匹配链接,使用它很容易单击具有多个链接的文本视图,如下所示:
Espresso.onView(ViewMatchers.withId(R.id.legal_privacy_tv)).perform(ViewActions.openLinkWithText("Privacy Statement"));
在我的情况下,我有 1 个单个文本视图,它与 2 个链接、隐私声明和法律声明相链接,使用上述方法我可以单独单击它们,而无需使用绑定 xy 或上面建议的其他方法。
这是我的解决方案。我正在使用反射,它很丑,但也许它为别人服务。
在我的例子中,spans 数组包含几种类型的 Span。我关心的是某种内部匿名类,因此 getClass().getSimpleName() 返回空字符串。该实例包含一个包含 URLSpan 的私有字段
private void clickOnSpan(TextView textView, CharSequence spanContent) {
SpannableString completeText = (SpannableString) textView.getText();
Layout textViewLayout = textView.getLayout();
Object[] spans = completeText.getSpans(0, completeText.length(), Object.class);
Object spanToLocate = null;
for (Object span : spans) {
if (!span.getClass().getSimpleName().equals(""))
continue;
try {
Field[] fields = span.getClass().getDeclaredFields();
fields[1].setAccessible(true);
URLSpan urlSpan = (URLSpan) fields[1].get(span);
if (urlSpan.getURL().equals(spanContent)) {
spanToLocate = span;
break;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int endOffsetOfClickedText = completeText.getSpanEnd(spanToLocate);
float endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(endOffsetOfClickedText);
int clickedTextLine = textViewLayout.getLineForOffset(endOffsetOfClickedText);
int yEndCoordinateOfClickedText = textViewLayout.getLineBottom(clickedTextLine);
onView(withId(textView.getId())).perform(clickXY(Float.valueOf(endXCoordinatesOfClickedText).intValue(), yEndCoordinateOfClickedText / 2));
}
参考:
clickXY:按边界/坐标单击
手动单击链接时是否有效?Espresso 会像用户点击一样将保存事件发送到屏幕,所以如果它不起作用(假设它点击相同的坐标),我会感到惊讶。话虽如此,如果您的链接在外部应用程序中启动 Activity,则仪器测试将由于安全限制而失败。目前无法使用 Espresso 解决此问题。
虽然票数最高的答案是正确的,但也许我可以在馅饼上加一点糖霜。因此,就我而言,我还想在单击链接时验证是否发送了正确的意图,我最近发现在 espresso 中有一个非常方便的子库,用于这种确切的场景:
androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
在@After
测试调用方法中Intents.init()
并在@Before
测试调用方法中Intents.release()
在@Test
方法中,做这样的事情 -
@Test
fun testClickingUrlInTextView() {
// preparing
val link = "www.stackoverflow.com"
val expectingIntent = Matchers.allOf(IntentMatchers.hasAction(Intent.ACTION_VIEW), IntentMatchers.hasData(link));
// mocking intent to prevent actual navigation during test
Intents.intending(expectingIntent).respondWith(new ActivityResult(0, null));
// performing action
onView(Matchers.allOf(withId(R.id.textview), withText(link)))
.perform(openLinkWithText(link));
// asserting our expected intent was recorded
Intents.intended(expectingIntent);
}
因此,通过以上述方式构建测试,我不仅能够断言导航意图,而且能够使测试不那么不稳定,因为它能够在任何设备上运行,无论该设备是否安装了应用程序处理该链接。(除非您希望它在特定的应用程序中打开,顺便说一句,您也可以使用上面的 espresso 子库来做到这一点。)