UiScrollable在Android uiautomator中不起作用

有没有人尝试Android UITesting框架UITesting ? 当我使用类UiScrollabl “在可滚动对象中查找某些对象时,如果可滚动对象的长度太长(需要刷两次才能find它),它就找不到对象,就像”Developer options“中的“设置”应用。有没有人有同样的问题?

我通过覆盖UiScrollable类来修复它。

 public class UiScrollable extends com.android.uiautomator.core.UiScrollable { public UiScrollable(UiSelector container) { super(container); } @Override public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { if (exists(getSelector().childSelector(selector))) { return (true); } else { System.out.println("It doesn't exist on this page"); // we will need to reset the search from the beginning to start search scrollToBeginning(getMaxSearchSwipes()); if (exists(getSelector().childSelector(selector))) { return (true); } for (int x = 0; x < getMaxSearchSwipes(); x++) { System.out.println("I'm going forward a page: " + x); if(!scrollForward() && x!=0) { // x!=0 is the hack return false; } if(exists(getSelector().childSelector(selector))) { return true; } } } return false; } } 

我复制了源代码: UiScrollable.java (可能在某些时候过时,要小心),只需更改if(!scrollForward() && x!=0)行。

根据我的观察,在Google的ui测试页面上的示例代码的情况下滚动设置应用程序的应用程序屏幕, scrollForwards()方法在第一次尝试时失败。 天知道为什么。

上面简单地说如果它在第一个卷轴上失败,则继续进行。 如果它无法在第二个滚动滚动,那么它确实会返回失败。

要查找视图中需要滚动的任何元素,我使用了下面提到的方法,它似乎工作正常。

 public void searchForText(String searchText) throws UiObjectNotFoundException { UiScrollable textScroll = null; UiObject text = null; if (searchText != null) { textScroll = new UiScrollable(new UiSelector().scrollable(true)); textScroll.scrollIntoView(new UiSelector().text(searchText)); text = new UiObject(new UiSelector().text(searchText)); text.click(); } } 

你能否提供更多细节,例如:

  • 你使用的是哪个版本的adt?
  • 哪个版本的Android是在/中运行的测试?

我问这些问题的原因是因为UIAutomator存在一些特定于版本的问题。 例如,我发现在Android 4.2.2的设备上运行的滚动问题看起来与您提到的类似。 我编写了一个解决方法,如果标准的Android方法似乎没有find我希望可用的元素,我的代码会滚动。

我在这里重现了我的代码的本质,你可以在http://blog.bettersoftwaretesting.com/?p=84find完整的例子。

  // The following loop is to workaround a bug in Android 4.2.2 which // fails to scroll more than once into view. for (int i = 0; i < maxSearchSwipes; i++) { try { appToLaunch = appViews.getChildByText(selector, nameOfAppToLaunch); if (appToLaunch != null) { // Create a UiSelector to find the Settings app and simulate // a user click to launch the app. appToLaunch.clickAndWaitForNewWindow(); break; } } catch (UiObjectNotFoundException e) { System.out.println("Did not find match for " + e.getLocalizedMessage()); } for (int j = 0; j < i; j++) { appViews.scrollForward(); System.out.println("scrolling forward 1 page of apps."); } } 

注意:我不知道此代码是否可以解决您的问题,因为我没有您的应用程序的示例。 如果您能够发布测试和相关UI的XML布局,则可以更轻松地诊断问题。

对于UiDevicedrag()我通常比使用Scrollable的方法更幸运。

我也遇到getChildByText只滚动一次,我试着追踪它。 我发现根本原因可能来自系统。

当你调用getChildByText ,它的流程是:

 getChildByText -> scrollIntoView -> scrollForward -> scrollSwipe 

scrollSwipe ,系统将运行swipe命令,wait,而不是查找所有AccessibilityEvent并在当前屏幕中过滤AccessibilityEvent.TYPE_VIEW_SCROLLED 。 此步骤使UiScrollable再次滚动或最后检查它。

但是bug就在这里,系统无法返回AccessibilityEvent

 public boolean scrollSwipe(final int downX, final int downY, final int upX, final int upY, final int steps) { Runnable command = new Runnable() { @Override public void run() { swipe(downX, downY, upX, upY, steps); } }; // Collect all accessibility events generated during the swipe command and get the // last event ArrayList events = new ArrayList(); runAndWaitForEvents(command, new EventCollectingPredicate(AccessibilityEvent.TYPE_VIEW_SCROLLED, events), Configurator.getInstance().getScrollAcknowledgmentTimeout()); //**Root cause** //Some times the events list size will be 0 , //but in fact it can scroll again. Log.e(LOG_TAG,"events size = " + events.size()); AccessibilityEvent event = getLastMatchingEvent(events, AccessibilityEvent.TYPE_VIEW_SCROLLED); if (event == null) { // end of scroll since no new scroll events received recycleAccessibilityEvents(events); return false; } ... .. . } 

我认为最好的方法是覆盖代码并定义合适的MaxSearchSwipes ,如果项目超过此大小,则使测试失败。

 public class UiScrollableFix extends UiScrollable { public UiScrollableFix(UiSelector container) { super(container); } @Override public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { Tracer.trace(selector); // if we happen to be on top of the text we want then return here UiSelector childSelector = getSelector().childSelector(selector); if (exists(childSelector)) { return (true); } else { // we will need to reset the search from the beginning to start search scrollToBeginning(getMaxSearchSwipes()); if (exists(childSelector)) { return (true); } for (int x = 0; x < getMaxSearchSwipes(); x++) { Log.e("test", "x=" + x); boolean scrolled = scrollForward(); if (exists(childSelector)) { return true; } //For avoiding the scroll fail. // if (!scrolled && x!=0) { // return false; // } } } return false; } } 
 scrollableObject.scrollIntoView(btn_1); try {if(scrollableObject.scrollIntoView(btn_1)) btn_1.click(); } catch (UiObjectNotFoundException e){ System.out.print("error1: "+e); } 

不确定这是否可以帮到你,但这就是我在我的应用程序中所做的。 第一行是让它滚动直到findbtn_1,然后如果它find了对象,它将对它执行单击。