我正在使用以下代码,尝试设置Espresso:import android.support.test.espresso.Espresso;import android.support.test.espresso.contrib.RecyclerViewActions;import android.support.test.espresso.matcher.ViewMatchers;import android.support.test.rule.ActivityTestRule;import android.support.test.runner.AndroidJUnit4;import org.junit.Rule;import org.junit.Test;import org.junit.runner.RunWith;import static android.support.test.espresso.action.ViewActions.click;@RunWith(AndroidJUnit4.class)public class EspressoTest { @Rule public ActivityTestRule<MainActivity> firstRule = new ActivityTestRule<>(MainActivity.class); @Test public void testRecyclerViewClick() { Espresso.onView(ViewMatchers.withId(R.id.recycler_view_ingredients)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); }} }它不会成功运行,我也不明白为什么。下面是错误: Caused by: java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints:(is assignable from class: class android.support.v7.widget.RecyclerView and is displayed on the screen to the user)Target view: "RecyclerView{id=2131165335, res-name=recycler_view_ingredients, visibility=VISIBLE, width=1440, height=0, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=true, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.support.constraint.ConstraintLayout$LayoutParams@caad301, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=0}"at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:245)at android.support.test.espresso.ViewInteraction.access$100(ViewInteraction.java:63)at android.support.test.espresso.ViewInteraction$1.call(ViewInteraction.java:153)at android.support.test.espresso.ViewInteraction$1.call(ViewInteraction.java:150)完整的Github回购:https://github.com/troy21688/KitchenPal编辑:测试实际上通过了模拟器,但没有通过我的实际手机(Google Nexus 6)。它使我相信,这与每个设备上的屏幕尺寸呈现方式有关。 最佳答案 您ID为RecyclerView的recycler_view_ingredients的高度为wrap_content,因此当它没有子级或适配器为空时,高度将为0。该错误表示将不执行操作,因为目标视图不会显示(RecyclerView),这也意味着当时尚未加载数据。您的应用程序正在异步地在其他线程上加载数据,然后在完全加载后在主线程上更新height=0。作为一件事情实际上,Espresso仅在主线程上进行同步,因此当您的应用开始在后台加载数据时,它认为该应用的主线程已处于空闲状态,因此它将继续执行操作,这可能会失败,也可能不会失败取决于设备性能。解决此问题的一种简单方法是增加一些延迟,例如:Thread.sleep(1000);onView(withId(R.id.recycler_view_ingredients)).perform(actionOnItemAtPosition(0, click()));或者,解决此问题的一种优雅方法是使用RecyclerView:onView(withId(R.id.recycler_view_ingredients)) .perform( waitUntil(hasItemCount(greaterThan(0))), // wait until data has loaded actionOnItemAtPosition(0, click()));以下是一些免费课程:public static Matcher<View> hasItemCount(Matcher<Integer> matcher) { return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { @Override public void describeTo(Description description) { description.appendText("has item count: "); matcher.describeTo(description); } @Override protected boolean matchesSafely(RecyclerView view) { return matcher.matches(view.getAdapter().getItemCount()); } };}public static ViewAction waitUntil(Matcher<View> matcher) { return actionWithAssertions(new ViewAction() { @Override public Matcher<View> getConstraints() { return ViewMatchers.isAssignableFrom(View.class); } @Override public String getDescription() { StringDescription description = new StringDescription(); matcher.describeTo(description); return String.format("wait until: %s", description); } @Override public void perform(UiController uiController, View view) { if (!matcher.matches(view)) { LayoutChangeCallback callback = new LayoutChangeCallback(matcher); try { IdlingRegistry.getInstance().register(callback); view.addOnLayoutChangeListener(callback); uiController.loopMainThreadUntilIdle(); } finally { view.removeOnLayoutChangeListener(callback); IdlingRegistry.getInstance().unregister(callback); } } } });}private static class LayoutChangeCallback implements IdlingResource, View.OnLayoutChangeListener { private Matcher<View> matcher; private IdlingResource.ResourceCallback callback; private boolean matched = false; LayoutChangeCallback(Matcher<View> matcher) { this.matcher = matcher; } @Override public String getName() { return "Layout change callback"; } @Override public boolean isIdleNow() { return matched; } @Override public void registerIdleTransitionCallback(ResourceCallback callback) { this.callback = callback; } @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { matched = matcher.matches(v); callback.onTransitionToIdle(); }}