Robolectric buildActivity() с шпионами Mockito?

Мне кажется, что создание Activity unit test с утилитами жизненного цикла Robolectric (начиная с Robolectric.buildActivity()) и шпионаже в отношении одной и той же операции с шпионами Mockito являются взаимоисключающими.

Поскольку buildActivity() управляет конструкцией объекта Activity, единственным местом для добавления шпиона для Activity является вызов buildActivity(). Однако шпион не работает должным образом, когда он добавляется после факта.

Это особенно верно при шпионаже за побочными эффектами методов жизненного цикла ActivityController, таких как create(), start() и resume(). Я предполагаю, что это происходит потому, что ActivityController содержит ссылку на "реальный" объект Activity, а не на шпион, который был добавлен позже.

Итак, есть ли способ отслеживать действие, которое тестируется с помощью Robolectric, так что шпион работает правильно при вызове методов жизненного цикла через Robolectric ActivityController?

Ответы

Ответ 1

По крайней мере, для случая, когда действие не является объектом, находящимся под тестированием, а только фиктивная активность, которая содержит тестируемый фрагмент, можно ввести макет в тестовую активность, которая может проверять взаимодействие с активностью через коммуникационный интерфейс между фрагментом и активностью (после http://developer.android.com/training/basics/fragments/communicating.html).

Ответ 2

Ответ заключается в использовании отражения для замены "реального" объекта Activity в ActivityController.

@Test
public void someTestMethod() throws NoSuchFieldException, IllegalAccessException {
    ActivityController<LoginActivity> ac = Robolectric.buildActivity(LoginActivity.class);
    LoginActivity spiedActivity = spy(ac.get());

    replaceComponentInActivityController(ac, spiedActivity);

    ac.create();

    // do your work
 }

public static void replaceComponentInActivityController(ActivityController<?> activityController, Activity activity)
        throws NoSuchFieldException, IllegalAccessException {
    Field componentField = ComponentController.class.getDeclaredField("component");
    componentField.setAccessible(true);
    componentField.set(activityController, activity);
}

Я тестирую его на Robolectric 3.1, и это нормально.