如何编写Robolectric单元测试以测试回收者视图项目的向左滑动

时间:2019-02-21 11:23:57

标签: android robolectric

*我正在编写单元测试用例以测试recyclerview项的向左滑动。我尝试使用此代码。但这不起作用

代码段:


float x = 0.0f;
float y = 0.0f;

int metaState = 0;
MotionEvent event = MotionEvent.obtain(
        downTime,
        eventTime,
        MotionEvent.ACTION_DOWN,
        x,
        y,
        metaState
);

MotionEvent moveEvent = MotionEvent.obtain(
        downTime,
        eventTime,
        MotionEvent.ACTION_MOVE,
        30,
        y,
        metaState
);
MotionEvent upEvent = MotionEvent.obtain(
        downTime,
        eventTime,
        MotionEvent.ACTION_UP,
        x,
        y,
        metaState
);

recylerView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.regular_card).dispatchTouchEvent(event);
recylerView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.regular_card).dispatchTouchEvent(moveEvent);
recylerView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.regular_card).dispatchTouchEvent(upEvent);*

1 个答案:

答案 0 :(得分:0)

此扩展功能可以为您提供帮助:

fun ViewGroup.performSwipeToLeft(target: View) {
    this.performSwipe(target, distanceX = -this.width * .5f, distanceY = 0f)
}
fun ViewGroup.performSwipeToRight(target: View) {
    this.performSwipe(target, distanceX = +this.width * .5f, distanceY = 0f)
}
fun ViewGroup.performSwipeToTop(target: View) {
    this.performSwipe(target, distanceX = 0f, distanceY = -this.height * .5f)
}
fun ViewGroup.performSwipeToBottom(target: View) {
    this.performSwipe(target, distanceX = 0f, distanceY = +this.width * .5f)
}

fun ViewGroup.performSwipe(target: View, distanceX: Float, distanceY: Float) {
    val parentCoords = intArrayOf(0, 0)
    this.getLocationInWindow(parentCoords)

    val childCoords = intArrayOf(0, 0)
    target.getLocationInWindow(childCoords)

    val initGlobalX = childCoords[0].toFloat() + 1f
    val initGlobalY = childCoords[1].toFloat() + 1f

    val initLocalX = (childCoords[0] - parentCoords[0]).toFloat() + 1f
    val initLocalY = (childCoords[1] - parentCoords[1]).toFloat() + 1f

    val downTime = SystemClock.uptimeMillis()
    var eventTime = SystemClock.uptimeMillis()

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            eventTime,
            MotionEvent.ACTION_DOWN,
            initGlobalX,
            initGlobalY,
            0
        ).apply {
            setLocation(initLocalX, initLocalY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )

    val steps = 20
    var i = 0
    while (i in 0..steps) {
        val globalX = initGlobalX + i * distanceX / steps
        val globalY = initGlobalY + i * distanceY / steps
        val localX = initLocalX + i * distanceX / steps
        val localY = initLocalY + i * distanceY / steps
        if (globalX <= 10f || globalY <= 10f) {
            break
        }
        this.dispatchTouchEvent(
            MotionEvent.obtain(
                downTime,
                ++eventTime,
                MotionEvent.ACTION_MOVE,
                globalX,
                globalY,
                0
            ).apply {
                setLocation(localX, localY)
                source = InputDevice.SOURCE_TOUCHSCREEN
            }
        )
        i++
    }

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            ++eventTime,
            MotionEvent.ACTION_UP,
            initGlobalX + i * distanceX,
            initGlobalY + i * distanceY,
            0
        ).apply {
            setLocation(initLocalX + i * distanceX, initLocalY + i * distanceY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )
}

在您的情况下,您可以按以下方式使用它:

recylerView.performSwipeToLeft(recyclerView.getChildAt(0))

滑动动画也可以与SystemClock.uptimeMillis()绑定。因此,您需要在测试前添加@LooperMode(LooperMode.Mode.PAUSED),然后使用ShadowSystemClock.advanceBy 就我而言,是:

@Test
    @LooperMode(LooperMode.Mode.PAUSED)
    fun swipeItem_itemDeleted() {
        ......
        listView.performSwipeToLeft(listView.getChildAt(1))
        while (!ShadowLooper.getShadowMainLooper().isIdle) {
            ShadowSystemClock.advanceBy(Duration.ofMillis(5))
            try {
                ShadowLooper.runMainLooperOneTask()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        assertEquals(... )
    }