【问题标题】:Android Espresso and LinkifyAndroid Espresso 和 Linkify
【发布时间】:2014-04-14 10:35:19
【问题描述】:

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

我尝试单击包含该链接的 TextView,但无法打开该链接。

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

【问题讨论】:

    标签: linkify ui-testing android-espresso


    【解决方案1】:

    我发现了一个更简单的方法,在ViewActions中有一个方法叫openLinkWithText,它使用linkTextMatcher作为匹配器来匹配链接,用这个就很轻松点击带有多个链接的文本视图,如下所示:

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

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

    【讨论】:

      【解决方案2】:

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

      在我的例子中,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)); 
      }
      

      参考资料:

      点击XY:Click by bounds / coordinates

      How get coordinate of a ClickableSpan inside a TextView?

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 当我手动点击链接时,链接会按预期工作。在这种情况下,它将打开同一应用程序的另一个活动,因此不应该有任何上下文丢失问题。问题是我现在才如何使用 espresso 执行点击视图,但我不知道如何点击 TextView 的单词或短语。如果 Espresso 能让你做到这一点,我会很棒。
        • 您点击 TextView 中的文本:onView(withText("mytext")).perform(click());
        • 你所做的是点击包含文本的视图,而不是文本本身。
        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-10
          • 1970-01-01
          • 1970-01-01
          • 2011-04-23
          • 2023-03-10
          • 2016-02-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多