Android:Espresso:如何在RecyclerView的特定位置获取项目?

时间:2019-04-12 14:09:56

标签: android android-recyclerview android-espresso

Android Studio 3.2。

我有一个活动.sidebar-mobile-transition { width: 100%; z-index: 0; background-color: white; position: fixed; bottom: 0; overscroll-behavior: none; overflow-y: scroll; overflow-x: auto; -webkit-overflow-scrolling: touch; } .sidebar-mobile-header { top: 0; position: fixed; height: 50px; width: 100%; background: black; color: white; z-index: 10; -webkit-transform: translate3d(0,0,0); } ,它显示项目列表(TradesActivity)。该列表由Trader显示。

我需要编写下一个Espresso测试。 如果RecyclerView,则项目的背景颜色为红色。其他背景颜色为绿色。我按仓位找到交易者。

所以我的Espresso测试必须执行以下步骤:

  1. 获取特定头寸的交易者(例如6)
  2. 检查trader.getRunning() == true
  3. 如果为true,则检查textView的背景

Espresso如何做到这一点?

这是我的解决方案。这是一个好的解决方案吗?

trader.running

我的自定义ViewAssertion的代码段:

    @Rule
    @JvmField
    var activityActivityTestRule = ActivityTestRule(TradersActivity::class.java)

@Test
fun itemList_itemContainerBackgrounColor() {
    // scroll to position
    onView(withId(R.id.tradersRecyclerView))
            .perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(CHECK_ITEM_LIST_POS, swipeLeft()))
    // check
    onView(withId(R.id.tradersRecyclerView)).check(hasCorrectBackgroundColorAtPosition(CHECK_ITEM_LIST_POS, R.id.itemContainer))
}

但是我得到了错误:

class TraderViewAssertion {

    companion object {
        fun hasCorrectBackgroundColorAtPosition(position: Int, @IdRes resId: Int): ViewAssertion {
            return object : ViewAssertion {

                override fun check(view: View, exception: NoMatchingViewException) {
                    if (view !is RecyclerView) {
                        throw exception
                    }
                    val trader = (view.adapter as TraderListItemAdapter).getItem(position) as Trader
                    val itemView = view.findViewHolderForAdapterPosition(position)!!.itemView.findViewById<View>(resId) as TextView
                    val itemViewColorDrawable = itemView.getBackground() as ColorDrawable
                    val colorCode = itemViewColorDrawable.color
                    if (trader.isRunning) {
                        if (DateUtil.getDiffMinutes(Date(trader.last_iteration_time), Date()) > 1) {
                            Assert.assertTrue("Wrong color at position $position", (colorCode == R.color.trade_error_color))
                        } else {
                            Assert.assertTrue("Wrong color at position $position", (colorCode == R.color.trade_running_color))
                        }
                    } else {
                        Assert.assertTrue("Wrong color at position $position", (colorCode == R.color.trade_not_running_color))
                    }
                }
            }
        }
    }
}

4 个答案:

答案 0 :(得分:0)

您可以这样创建一个自定义匹配器:

public static Matcher<View> withIndex(final Matcher<View> matcher, final int index) {
return new TypeSafeMatcher<View>() {
    int currentIndex = 0;

    @Override
    public void describeTo(Description description) {
        description.appendText("with index: ");
        description.appendValue(index);
        matcher.describeTo(description);
    }

    @Override
    public boolean matchesSafely(View view) {
        return matcher.matches(view) && currentIndex++ == index;
    }
};

}

答案 1 :(得分:0)

您没有提供足够的信息来完整地回答您的问题,但这应该可以引导您正确的方向。我不得不提一下,我宁愿在测试期间创建特定条件,并在给定位置检查给定列表项,然后深入检查数据和视图。

匹配器(伪代码):

    public static ViewAssertion hasCorrectBackgroundColorAtPosition(int position, @IdRes int id) {
        return new ViewAssertion() {
            @Override
            public void check(View view, NoMatchingViewException exception) {
                if (!(view instanceof RecyclerView)) {
                    throw exception;
                }

                RecyclerView rv = (RecyclerView) view;
                Trader item = ((YourAdapter) rv.getAdapter()).getItem(position);

                View itemView = rv.findViewHolderForAdapterPosition(position).itemView.findViewById(id);

        if(item.running) {
                Assert.assertTrue(
                        "Wrong color at position " + position,
                        itemView.getBackground().getColor() == R.color.colorA
                );
                } else {
                Assert.assertTrue(
                        "Wrong color at position " + position,
                        itemView.getBackground().getColor() == R.color.colorB
                );
                }

            }
        };
    }

使用方法:

onView(yourRecyclerView).check(hasCorrectBackgroundColorAtPosition(123, R.id.yourTextViewId));

答案 2 :(得分:0)

我找到了解决方法:

 @Test
    fun itemList_itemContainerBackgrounColor() {
        // scroll to position
        onView(withId(R.id.tradersRecyclerView))
                .perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(CHECK_ITEM_LIST_POS, swipeLeft()))
        // check
        val recyclerView = activityActivityTestRule.activity.findViewById<View>(R.id.tradersRecyclerView) as RecyclerView
        val trader = (recyclerView.adapter as TraderListItemAdapter).getItem(CHECK_ITEM_LIST_POS) as Trader
        val itemContainer = recyclerView.findViewHolderForAdapterPosition(CHECK_ITEM_LIST_POS)!!.itemView.findViewById<View>(R.id.itemContainer) as ConstraintLayout
        val colorCode = (itemContainer.background.current as ColorDrawable).color
        if (trader.isRunning) {
            if (DateUtil.getDiffMinutes(Date(trader.last_iteration_time), Date()) > 1) {
                Assert.assertTrue("Wrong color at position $CHECK_ITEM_LIST_POS", (colorCode == ContextCompat.getColor(itemContainer.context, R.color.trade_error_color)))
            } else {
                Assert.assertTrue("Wrong color at position $CHECK_ITEM_LIST_POS", (colorCode == ContextCompat.getColor(itemContainer.context, R.color.trade_running_color)))
            }
        } else {
            Assert.assertTrue("Wrong color at position $CHECK_ITEM_LIST_POS", (colorCode == ContextCompat.getColor(itemContainer.context, R.color.trade_not_running_color)))
        }
    }

答案 3 :(得分:0)

Daniel Beleza answer 有 Kotlin 版本:

private fun withIndex(matcher: Matcher<View>, index: Int): Matcher<View> {
    return object : TypeSafeMatcher<View>() {
        private var currentIndex = 0

        override fun describeTo(description: Description?) {
            description?.appendText("with index: ");
            description?.appendValue(index);
            matcher.describeTo(description);
        }

        override fun matchesSafely(view: View?): Boolean {
            return matcher.matches(view) && currentIndex++ == index;
        }
    }
}