Как обновить элементы пользовательского интерфейса активности с помощью методов тестирования Espresso?

Я пытаюсь написать тестовый пример для своей деятельности. У меня есть метод в моей деятельности, который обновляет мой пользовательский интерфейс.

public void setBooking(Booking booking)
{
    if (booking == null)
    {
        return;
    }

    this.mBooking = booking;
    this.mBookingExt.updateUI();
}

и это мой тестовый класс:

@RunWith(AndroidJUnit4.class)
public class LocatingActivityTest
{
    @Rule
    public ActivityTestRule<BookingActivity> mActivityTestRule = new ActivityTestRule<>(BookingActivity.class);

    private BookingActivity mBookingActivity;

    @Before
    public void setup()
    {
        mBookingActivity = mActivityTestRule.getActivity();
        mBookingActivity.setBooking(BookingTest.getStandardTaxi()); // << My Fake Booking Object

        onView(withId(R.id.book_now)).perform(click());
    }

    @Test
    public void viewsMustBeVisible()
    {
        onView(withId(R.id.locating_text)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.sonarView)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.cancel_booking)).check(matches(isCompletelyDisplayed()));
    }
}

Я получаю следующую ошибку при запуске теста:

android.view.ViewRootImpl$CalledFromWrongThreadException: Только исходный поток, создавший иерархию представлений, может касаться своих представлений.

Я думаю, что @Before работает в потоке пользовательского интерфейса, поэтому понятия не имею, откуда эта жалоба! Это моя ссылка (ActivityTestRule расширяет UiThreadTestRule).

Поэтому я решил немного изменить архитектуру класса. Итак, setup() и viewsMustBeVisible() изменились на это:

    @Before
    public void setup()
    {
        mBookingTaxiActivity = mActivityTestRule.getActivity();
    }

    @UiThreadTest // from android.support.test.annotation.UiThreadTest
    public void viewsMustBeVisible()
    {
        mBookingTaxiActivity.setBooking(BookingTest.getStandardTaxi()); // << My Fake Booking Object

        onView(withId(R.id.fab_booking)).perform(click());
        onView(withId(R.id.booking_book_now)).check(matches(isEnabled()));
        onView(withId(R.id.booking_book_now)).perform(click());

        onView(withId(R.id.locating_text)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.sonarView)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.locating_cancel_booking)).check(matches(isCompletelyDisplayed()));
    }

Однако на этот раз я получаю следующую ошибку:

java.lang.Exception: нет исполняемых методов

Наконец, я изменил метод выше, чтобы запустить тест в потоке пользовательского интерфейса:

    @Test
    public void viewsMustBeVisible()
    {
        mBookingTaxiActivity.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                mBookingTaxiActivity.setBooking(BookingTest.getStandardTaxi()); // << My Fake Booking Object

                onView(withId(R.id.fab_booking)).perform(click());
                onView(withId(R.id.booking_book_now)).check(matches(isEnabled()));
                onView(withId(R.id.booking_book_now)).perform(click());

                onView(withId(R.id.locating_text)).check(matches(isCompletelyDisplayed()));
                onView(withId(R.id.sonarView)).check(matches(isCompletelyDisplayed()));
                onView(withId(R.id.locating_cancel_booking)).check(matches(isCompletelyDisplayed()));
        });
    }

Проблема здесь в том, что тест никогда не делается. Я жду 6-7 минут, а его индикатор прогресса все еще крутится и, кажется, никогда не будет выполнен.

Думаю, я изучил все способы обновления моего объекта Booking, а также элементов пользовательского интерфейса.


person Hesam    schedule 16.02.2016    source источник


Ответы (1)


Круто, я получил это после многих часов. Я не уверен, в чем разница, но я переместил поток пользовательского интерфейса в Activity. Новый метод тестирования выглядит следующим образом:

    @Test
    public void viewsMustBeVisible()
    {
        onView(withId(R.id.fab_booking)).perform(click());

        mBookingTaxiActivity.setTestBooking(BookingTest.getStandardTaxi());

        onView(withId(R.id.booking_book_now)).check(matches(isEnabled()));
        onView(withId(R.id.booking_book_now)).perform(click());

        onView(withId(R.id.locating_text)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.sonarView)).check(matches(isCompletelyDisplayed()));
        onView(withId(R.id.locating_cancel_booking)).check(matches(isCompletelyDisplayed()));
    }

и я создал метод на стороне активности для обновления моего объекта:

    // Required just for Testing purposes
    @VisibleForTesting
    public void setTestBooking(Booking booking)
    {
        if (booking == null)
        {
            return;
        }

        this.mBooking = booking;

        this.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                BookingActivity.this.mBookingExt.updateUI();
                findViewById(R.id.booking_book_now).setEnabled(true);
            }
        });
    }

Надеюсь, это поможет вам, если у вас есть такая же проблема.

person Hesam    schedule 17.02.2016