自动测试中的Android Espresso谓词?

自动测试中的Android Espresso谓词?,android,ui-automation,android-espresso,Android,Ui Automation,Android Espresso,是否有任何方法可以实现与iOS Xcode的NSPredicate中类似的谓词来等待Android Espresso中的某些事件 对于iOS,您可以调用expectationForPredicate和waitForExpectationsWithTimeout作为xtest的一部分 我有两个类似的iOS和Android应用程序,我一直负责测试。在iOS中,我可以执行以下操作: let app = XCUIApplication(); let condition = app.staticT

是否有任何方法可以实现与iOS Xcode的
NSPredicate
中类似的谓词来等待Android Espresso中的某些事件

对于iOS,您可以调用
expectationForPredicate
waitForExpectationsWithTimeout
作为
xtest
的一部分

我有两个类似的iOS和Android应用程序,我一直负责测试。在iOS中,我可以执行以下操作:

  let app = XCUIApplication();
  let condition = app.staticTexts["Text That Displays After Event"]
  let exists = NSPredicate(format: "exists == true")
  expectationForPredicate(exists, evaluatedWithObject: condition, handler: nil)
  waitForExpectationsWithTimeout(5, handler: nil)

  XCTAssert(app.staticTexts["Text That Displays After Event"].exists)
在Android中,我能做的最好的事情就是注册一个空闲的资源并等待几秒钟,然后检查事件是否手动发生

  long waitingTime = 3 * DateUtils.SECOND_IN_MILLIS;
  IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
  IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
  IdlingResource idlingResource = new ElapsedTimeIdlingResource(waitingTime);
  Espresso.registerIdlingResources(idlingResource);

  onView(withId(R.id.id_in_next_event)).check(matches(isDisplayed()));

  Espresso.unregisterIdlingResources(idlingResource);

我相信一定有更好的方法来做到这一点。

大多数事情都可以通过
插装#waitForIdleSync()
方法来完成。这将等待处理所有UI事件,然后继续。假设您有一个ID为
buttonId
的按钮,按下该按钮时,将显示ID为
hiddenView
的视图

如果您这样做:

private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();

@Test
public void checkViewIsRevealed() {
   onView(withId(R.id.buttonId)).perform(click());

   instrumentation.waitForIdleSync();

   onView(withId(R.id.hiddenView)).check(matches(isDisplayed());
}

因此,在此过程中,执行“单击”将调用
hiddenView
上的
View#setVisibility()
。然后,等待idle以确保所有UI操作都通过。然后检查是否显示了新视图。

您可以编写一个自定义的
视图操作
,等待
匹配器
变为真。 但只有当浓缩咖啡不需要自己等待时,才需要这样做。Espresso等待,例如,如果应用程序的主线程正在工作,或者如果
AsyncTask
正在运行

等待视图操作的实现方式如下:

public class WaitForCondition implements ViewAction {
    private static final long IDLING_INTERVAL = 50;
    private final Matcher<View> mCondition;
    private final long mTimeout;

    public WaitForCondition(final Matcher<View> condition, final long timeout) {
        mCondition = condition;
        mTimeout = timeout;
    }

    @Override
    public Matcher<View> getConstraints() {
        return isAssignableFrom(View.class);
    }

    @Override
    public String getDescription() {
        return String.format(Locale.US, "Waiting until the condition '%s' will become true (timeout %d ms)", getConditionDescription(), mTimeout);
    }

    private String getConditionDescription() {
        StringDescription description = new StringDescription();
        mCondition.describeTo(description);
        return description.toString();
    }

    @Override
    public void perform(final UiController uiController, final View view) {

        if (mCondition.matches(view)) {
            return;
        }
        final long timeOut = System.currentTimeMillis() + mTimeout;

        // Wait for the condition to become true
        while (System.currentTimeMillis() <= timeOut) {
            uiController.loopMainThreadForAtLeast(IDLING_INTERVAL);
            if (mCondition.matches(view)) {
                return;
            }
        }
        throw new PerformException.Builder()
                .withActionDescription(this.getDescription())
                .withViewDescription(HumanReadables.describe(view))
                .withCause(new RuntimeException(String.format(Locale.US,
                        "Condition '%s' did not become true after %d ms of waiting.", getConditionDescription(), mTimeout)))
                .build();
    }
}

谢谢,这个很好用。它甚至在等待截击请求,而这正是我所需要的。@Jack:我会厌倦的。这只等待所有UI操作完成。Volley是一个完全独立的异步库。我想你的下载操作真的很快(这很好,但稍后会爆炸)。@DeeV调用
waitForIdleSync()
绝对不是必需的。浓缩咖啡已经在等待应用程序空闲。
onView(withId(R.id.id_in_next_event)).perform(new WaitForCondition(matches(isDisplayed()), 3000));