11

我正在为我的基于 Espresso 的 Android 应用程序编写一些测试。单击 TextView 内的链接(使用 Linkify 类创建)后,我需要断言我看到的是正确的屏幕。

我尝试单击包含链接的 TextView,但链接不会打开。

是否有使用 Espresso 进行测试的正确方法(除了修改代码以使链接具有单独的 TextView)?

4

4 回答 4

15

我发现了一种更简单的方法,在ViewActions中有一个名为openLinkWithText的方法,它使用 linkTextMatcher 作为匹配器来匹配链接,使用它很容易单击具有多个链接的文本视图,如下所示:

Espresso.onView(ViewMatchers.withId(R.id.legal_privacy_tv)).perform(ViewActions.openLinkWithText("Privacy Statement")); 

在我的情况下,我有 1 个单个文本视图,它与 2 个链接、隐私声明和法律声明相链接,使用上述方法我可以单独单击它们,而无需使用绑定 xy 或上面建议的其他方法。

于 2016-04-24T19:08:11.217 回答
4

这是我的解决方案。我正在使用反射,它很丑,但也许它为别人服务。

在我的例子中,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:按边界/坐标单击

如何在 TextView 中获取 ClickableSpan 的坐标?

于 2014-09-24T07:30:04.053 回答
1

手动单击链接时是否有效?Espresso 会像用户点击一样将保存事件发送到屏幕,所以如果它不起作用(假设它点击相同的坐标),我会感到惊讶。话虽如此,如果您的链接在外部应用程序中启动 Activity,则仪器测试将由于安全限制而失败。目前无法使用 Espresso 解决此问题。

于 2014-03-17T16:06:41.950 回答
0

虽然票数最高的答案是正确的,但也许我可以在馅饼上加一点糖霜。因此,就我而言,我还想在单击链接时验证是否发送了正确的意图,我最近发现在 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 子库来做到这一点。)

于 2018-12-28T08:58:32.043 回答