Robolectric buildActivity() with Mockito spy?

2020-02-13 08:08发布

问题:

It seems to me that building an Activity unit test with Robolectric's lifecycle utilities (starting with Robolectric.buildActivity()) and spying on the same Activity with a Mockito spy are mutually exclusive.

Because buildActivity() controls the construction of the Activity object, the only place to add a spy for the Activity is after calling buildActivity(). However, the spy doesn't function properly when it's added after the fact.

This is especially true when spying for side effects of ActivityController lifecycle methods such as create(), start() and resume(). I assume this is because the ActivityController holds a reference to the "real" Activity object and not the spy that was added later.

So is there any way to spy an Activity that's being unit tested with Robolectric, such that the spy works properly when calling the lifecycle methods via Robolectric's ActivityController?

回答1:

The answer is using the reflection to replace the "real" Activity object in 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);
}

I test it by Robolectric 3.1, and it's ok.



回答2:

At least for the case where the activity is not the object under test, but only a dummy activity which hosts a fragment under test, it is possible to inject a mock into the test activity which can verify interactions with the activity via the communication interface between fragment and activity (following http://developer.android.com/training/basics/fragments/communicating.html).