Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to simulate a drag event on a ViewPager in Roboelectric?

I am a newbie in Android and Robolectric. I am trying to simulate (as the topic indicates it) a drag event on a viewpager.

I have ever implemented this code and it runs on the emulator.

The matter is mostly: how can I unit test it?

Here is the unit test:

/** imports are skipped **/

@RunWith(RobolectricTestRunner.class)
@Config(manifest = "/src/main/AndroidManifest.xml")
public class TestImages {

private ImageActivity activity;

@InjectResource(R.drawable.ic_launcher)
private static Drawable image;

@Spy
private final PicturesModel picturesModel = spy(new PicturesModelImpl());

/**
 * Last touched view
 */
private View lastTouchView;

/**
 * Last touched X coordinate
 */
private float lastTouchX;
/**
 * Last touched Y coordinate
 */
private float lastTouchY;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);

    final Module roboGuiceModule = RoboGuice.newDefaultRoboModule(Robolectric.application);
    final Module pictureModule = Modules.override(roboGuiceModule).with(new PictureModule());
    final Module testModule = Modules.override(pictureModule).with(new TestPictureModule(picturesModel));

    RoboGuice.setBaseApplicationInjector(Robolectric.application, RoboGuice.DEFAULT_STAGE, testModule);
    RoboInjector injector = RoboGuice.getInjector(Robolectric.application);
    injector.injectMembersWithoutViews(this);
}

@Test
public void scroll_image() {
    final Intent intent = new Intent(Robolectric.getShadowApplication().getApplicationContext(), ImageActivity.class);
    final Album album = new Album(1, "album_1", image);
    intent.putExtra("album", album);
    intent.putExtra("position", 2);
    intent.putExtra("imageId", 2L);

    // Get the activity
    activity = Robolectric.buildActivity(ImageActivity.class).withIntent(intent).create().get();
    final Point point = new Point();
    activity.getWindowManager().getDefaultDisplay().getSize(point);

    // Get a spy viewer otherwise viewPager's width is always 0
    final ViewPager viewPager = spy((ViewPager) activity.findViewById(R.id.viewPager));
    viewPager.setVisibility(View.VISIBLE);
    when(viewPager.getWidth()).thenReturn(point.x - 50);

    // First item sent by viewPager before swipe
    final int firstItem = viewPager.getCurrentItem();

    // Swipe
    drag(viewPager, 10F, 10F, point.x - 60F, 10F);

    // Next item after swipe
    final int secondItem = viewPager.getCurrentItem();

    // Comparison
    assertThat(firstItem).isEqualTo(2);
    assertThat(secondItem).isEqualTo(3);
}

public void touchDown(View view, float x, float y) {
    lastTouchX = x;
    lastTouchY = y;
    lastTouchView = view;

    sendMotionEvent(view, MotionEvent.ACTION_DOWN, x, y);
}

public void touchMove(float x, float y) {
    lastTouchX = x;
    lastTouchY = y;

    sendMotionEvent(lastTouchView, MotionEvent.ACTION_MOVE, x, y);
}

public void touchUp() {
    sendMotionEvent(
            lastTouchView, MotionEvent.ACTION_UP, lastTouchX, lastTouchY);

    lastTouchView = null;
}

public void drag(View view, float xStart, float yStart,
                 float xEnd, float yEnd) {
    touchDown(view, xStart, yStart);
    touchMove(xEnd, yEnd);
    touchUp();
}

private void sendMotionEvent(View view, int action, float x, float y) {

    int[] screenOffset = new int[2];
    view.getLocationOnScreen(screenOffset);

    MotionEvent event = MotionEvent.obtain(100, 200, action,
            x + screenOffset[0], y + screenOffset[1], 0);

    shadowOf(event).setPointerIds(1, 2);
    shadowOf(event).setPointerIndex(1);

    view.onTouchEvent(event);
    view.dispatchTouchEvent(event);
}
}

and the the activity:

public class ImageActivity extends RoboActivity {

    @Inject
    private PicturesModel picturesModel;

    @InjectView(R.id.viewPager)
    private ViewPager viewPager;

    private PagerAdapter pagerAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image);

        final Bundle bundle = getIntent().getExtras();
        if (bundle != null && !bundle.isEmpty()) {
            final long id = (long) bundle.get("imageId");
            final int position = (int) bundle.get("position");
            final Picture picture = picturesModel.getPicture(id);
            if (picture != null) {

                pagerAdapter = new ImageAdapter(this, picturesModel.getAllPictures((Album) bundle.get("album")));
                viewPager.setAdapter(pagerAdapter);
                viewPager.setCurrentItem(position, true);
            }
        }
    }
}

and this is the layout:

    <?xml version="1.0" encoding="utf-8"?>

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/viewPager" />

Does someone has an idea how to proceed or to tell me where is my mistake?

like image 634
frederic Avatar asked Feb 20 '14 21:02

frederic


1 Answers

I think you what you are looking for is the Espresso library.

It simulates UI Events and let you check the state of the view once you threw the event and it is really easy to use. Just don't forget to switch animations off in the developers settings.

like image 99
Vadim Caen Avatar answered Oct 16 '22 08:10

Vadim Caen