Как проверить фрагмент с помощью эспрессо

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

Однако Espresso не находит ни одного из видов внутри фрагмента. Он сбрасывает иерархию представления, и все пусто.

Я не хочу использовать действительную родительскую активность. Я хочу просто проверить этот фрагмент изолированно. Кто-нибудь сделал это? Есть ли образец с похожим кодом?

@RunWith(AndroidJUnit4.class)
class MyFragmentTest {
    @Rule
    public ActivityTestRule activityRule = new ActivityTestRule<>(
    TestActivity.class);

    @Test
    public void testView() {
       MyFragment myFragment = startMyFragment();
       myFragment.onEvent(new MyEvent());
       // MyFragment has a recyclerview. 
       //OnEvent is EventBus callback that in this test contains no data.
       //I want the fragment to display empty list text and hide the recyclerView
       onView(withId(R.id.my_empty_text)).check(matches(isDisplayed()));
       onView(withId(R.id.my_recycler)).check(doesNotExist()));
    }

    private MyFragment startMyFragment() {
         FragmentActivity activity = (FragmentActivity) activityRule.getActivity();
    FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
    MyFragment myFragment = new MyFragment();
    transaction.add(myFragment, "myfrag");
    transaction.commit();
    return myFragment;
    }
}

Ответ 1

Я буду делать следующим образом Создайте ViewAction следующим образом:

public static ViewAction doTaskInUIThread(final Runnable r) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isRoot();
        }

        @Override
        public String getDescription() {
            return null;
        }

        @Override
        public void perform(UiController uiController, View view) {
            r.run();
        }
    };
}

Затем используйте ниже, чтобы запустить код, который должен быть запущен в потоке пользовательского интерфейса

onView(isRoot()).perform(doTaskInUIThread(new Runnable() {
        @Override
        public void run() {
            //Code to add your fragment or anytask that you want to do from UI Thread
        }
    }));

ниже приведен пример тестового примера добавления иерархии представлений фрагментов

    @Test
public void testSelectionOfTagsAndOpenOtherPage() throws Exception{

    Runnable r = new Runnable() {
        @Override
        public void run() {
            //Task that need to be done in UI Thread (below I am adding a fragment)

        }
    };
    onView(isRoot()).perform(doTaskInUIThread(r));

}

Ответ 2

public class VoiceFullScreenTest {
    @Rule
    public ActivityTestRule activityRule = new ActivityTestRule<>(
            TestActivity.class);

    @Test
    public void fragment_can_be_instantiated() {
        activityRule.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                VoiceFragment voiceFragment = startVoiceFragment();
            }
        });
        // Then use Espresso to test the Fragment
        onView(withId(R.id.iv_record_image)).check(matches(isDisplayed()));
    }

    private VoiceFragment startVoiceFragment() {
        TestActivity activity = (TestActivity) activityRule.getActivity();
        FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
        VoiceFragment voiceFragment = new VoiceFragment();
        transaction.add(voiceFragment, "voiceFragment");
        transaction.commit();
        return voiceFragment;
    }


}

Вы можете запустить свой фрагмент из потока пользовательского интерфейса, как указано выше.

Ответ 3

Вероятно, вы забыли вставить фрагмент в иерархию представлений. Попробуйте определить контейнер-держатель для вашего фрагмента в макете TestActivity (например, FrameLayout с id fragment_container), а затем вместо просто add(myFragment, "tag") используйте add(R.id.fragment_container, myFragment, "tag") (этот метод). Я думаю, вы могли бы использовать метод replace с той же сигнатурой.

Ответ 5

Если вы в порядке, используя альфа-версии библиотек androidx, тогда вы можете использовать androidx.fragment:fragment-testing библиотеку для androidx.fragment:fragment-testing. На момент написания статьи последняя версия 1.1.0-alpha07.

Запуск фрагмента в вашем тестовом методе так же прост, как:

val fragmentArgs = Bundle()
androidx.fragment.app.testing.launchFragmentInContainer<MyFragment>(fragmentArgs)

Вы можете найти больше информации об этой библиотеке здесь.