如何在使用Robolectric时监视Activity

3

我是一名新手,正在学习Android,并在使用Robolectric进行单元测试。我遇到了以下问题。

我想要测试一个活动。

MainActivity.java

public class MainActivity extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks {

    private NavigationDrawerFragment mNavigationDrawerFragment;

    @Override
    protected void onCreate (Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);

        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));
    }

    @Override
    public void onNavigationDrawerItemSelected (int position) {
        ...
    }
}

这是测试类:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class MainActivityTests {

    private ActivityController<MainActivity> controller;
    private MainActivity activity;
    private MainActivity spy;

    @Test
    public void onCreate_shouldStartNavigationDrawerFragment () {

        controller = Robolectric.buildActivity(MainActivity.class);
        activity = controller.get();
        assertThat(activity).isNotNull();

        spy = spy(activity);
        spy.onCreate(null);

        verify(spy).onCreate(null);
    }
}

但我遇到了以下异常:

java.lang.IllegalStateException: 在onCreate()之前,Activity无法使用系统服务,位于spy.onCreate(null)的代码行。

我已经谷歌搜索了几个小时,并尝试过几种方法(盲目地),但没有成功。请问有人可以指导我吗?

你找到解决方法了吗? - conca
你尝试过调用 controller.create() 而不是 spy.onCreate(null) 吗? - Max Ch
请查看另一篇帖子,了解使用robolectric监视活动的答案。 - Riki
4个回答

2

以下是对我有效的解决方法。在监视活动之前,我使用attach()函数。已经在Robolectric 3.0上进行了测试。

private MainActivity spyActivity;

@Before
public void setUp(){

    MainActivity activity = Robolectric.buildActivity(MainActivity.class).attach().get();
    spyActivity = spy(activity);

    spyActivity.onCreate(null);

}

这不可行,因为在活动中 onCreate() 方法是 protected 的。 - azizbekian
@azizbekian 如果你在你的活动中将其覆盖为公共的话,就不会出现这种情况。 - undefined

1
你应该通过Robolectric来驱动Activity生命周期。参见: http://robolectric.org/activity-lifecycle/ 所以在你的情况下,你可以这样做:
controller = Robolectric.buildActivity(MainActivity.class);
activity = controller.get();
assertThat(activity).isNotNull();
spy = spy(activity);
controller.create();

注意:使用Robolectric进行测试时,监视活动生命周期通常没有意义,因为您是在驱动它,所以您只测试自己的方法调用是否执行。

今晚我会尝试这种方法。 我的重点测试onCreate方法只是为了确保创建了NavigationDrawerFragment,而不是活动的生命周期。 - kazbeel
2
我也认为MockitospyPowerMock应该只在特殊情况下使用。在过去的两年中,我没有在Robolectric中使用任何spyPowerMockito - Eugen Martynov
您提供的代码片段无法工作,因为被监测的活动不是由控制器处理的。非常感谢您的帮助。 我想我会放弃尝试检查片段是否已设置。 - kazbeel
2
我真的不明白为什么有人说我们不应该“mocking/spying”正在测试的活动。有时这些活动调用函数(比如getApplication()),会导致错误。我只想让我的活动返回一个模拟的应用程序对象,但如果不对正在测试的活动进行模拟,我就无法做到这一点。 - Caleb
@Davis,这可能应该放在另一个问题中,以便可以更详细地探讨。可能有其他更好的方法来实现你想要完成的目标。 - Alex Florescu

1
如果您有兴趣使用完全相同的控制器,并与活动的间谍一起工作,您可以通过反射修改控制器的内部类。请参阅以下方法:
public static <T extends Activity> T getSpy(ActivityController<T> activityController) {
    T spy = spy(activityController.get());
    ReflectionHelpers.setField(activityController, "component", spy);
    return spy;
}

ReflectionHelper在Robolectric中可用(在Robolectric 4.2上测试过)。然后它可以像这样初始化:
controller = Robolectric.buildActivity(MainActivity.class);
activity = getSpy(controller.get());

希望这能帮到你。

0

这意味着您必须首先调用onCreate()方法。它必须是第一个被调用的方法。


这是第一个方法,实际上也是唯一的方法。 - kazbeel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接