我正在使用Espresso进行一些简单的测试。其中一个是关于点击视图并检查是否显示了对话框。
我的问题是有时是有效的,有时则不然。它只在我检查对话框之前放置 sleep 时才会起作用。没有解决睡眠的任何解决方案?
这是我的代码(如此简单):
onView(withId(R.id.forgot_password)).perform(click());
// only works if use Thread.sleep(ms) here
onView(withText(R.string.reset_password)).check(matches(isDisplayed()));
编辑:
我正在使用静态助手显示对话框,但简化就是这样。而且我没有在中间执行任何后台任务。
final TextInputDialog textInputDialog = new
TextInputDialog.Builder(context)
.setTitle(titleId)
.setInputType(inputType)
.setHint(hintId)
.setPreFilledText(preFilledText)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(positiveButtonId, onTextSubmittedListener)
.create();
textInputDialog.show(textInputDialog);
谢谢!
答案 0 :(得分:3)
最后似乎问题是动画。要使make Espresso正常工作,需要在开发人员选项菜单中禁用动画。
在这种情况下,问题得以解决。但是在其他情况下,问题可能是一个后台任务,就像我的问题的评论所暗示的那样。所以我建议您查看 IdlingResource https://medium.com/azimolabs/wait-for-it-idlingresource-and-conditionwatcher-602055f32356#.pw55uipfj或此Espresso: Thread.sleep( );
答案 1 :(得分:1)
在某些情况下,禁用动画是不可能的:
在这些情况下,最简单的是等待元素显示。方法如下:
简单助手:
class WaifForUIUpdate {
public static void waifForWithId(@IdRes int stringId) {
ViewInteraction element;
do {
waitFor(500);
//simple example using withText Matcher.
element = onView(withText(stringId);
} while (!MatcherExtension.exists(element));
}
static void waitFor(int ms) {
final CountDownLatch signal = new CountDownLatch(1);
try {
signal.await(ms, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
}
}
来自twisterrob 的匹配
public class MatcherExtension {
@CheckResult
public static boolean exists(ViewInteraction interaction) {
try {
interaction.perform(new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return any(View.class);
}
@Override
public String getDescription() {
return "check for existence";
}
@Override
public void perform(UiController uiController, View view) {
// no op, if this is run, then the execution will continue after .perform(...)
}
});
return true;
} catch (AmbiguousViewMatcherException ex) {
// if there's any interaction later with the same matcher, that'll fail anyway
return true; // we found more than one
} catch (NoMatchingViewException ex) {
return false;
} catch (NoMatchingRootException ex) {
// optional depending on what you think "exists" means
return false;
}
}
}
<强>用法强>:
WaifForUIUpdate.waifForWithId(R.string.some_string);
//now do your validations
答案 2 :(得分:0)
我最终使用了不同于我的第一个答案的另一种方法,该方法也很有效,但是通过使用CountdownLatch
可以更轻松地适应任何情况。
这是代码:
public static boolean viewExists(final Matcher<View> viewMatcher, final long millis) throws InterruptedException {
final Boolean[] found = new Boolean[1];
final CountDownLatch latch = new CountDownLatch(1);
ViewAction action = new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return isRoot();
}
@Override
public String getDescription() {
return "wait for a specific view with id <" + viewMatcher.toString() + "> during " + millis + " millis.";
}
@Override
public void perform(final UiController uiController, final View view) {
uiController.loopMainThreadUntilIdle();
final long startTime = System.currentTimeMillis();
final long endTime = startTime + millis;
do {
for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
if (viewMatcher.matches(child)) {
Log.d(TAG, "perform: found match");
found[0] = true;
latch.countDown();
return;
}
}
uiController.loopMainThreadForAtLeast(50);
}
while (System.currentTimeMillis() < endTime);
found[0] = false;
latch.countDown();
}
};
onView(isRoot()).perform(action);
latch.await();
return found[0];
}
Google的方法是使用Idling resource类,但需要将测试代码插入生产apk,或使用风味和依赖注入模式来避免这种情况。