简体   繁体   English

Robolectric和Mockito监视Android活动

[英]Robolectric and Mockito spying Android Activity

This my second question related to Robolectric + Mockito. 这是我的第二个问题,与Robolectric + Mockito有关。 I've been struggling with this for a couple of days. 我一直在努力解决这个问题。 What i'm trying to do is to spy an Activity to test its onCreate() callback method. 我想要做的是窥探一个Activity来测试它的onCreate()回调方法。

I don't know how to drive the spied Activity through its lifecycle in order to call onCreate(). 我不知道如何在其生命周期中驱动间谍活动以调用onCreate()。 This is my Activity: 这是我的活动:

public class MainActivity extends FragmentActivity {

    public Session session; // Facebook session

    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        session = getActiveSession();
        if (session == null ) {
            // ...
        } else {
            if (sessionClosed()) {
                LoginFragment fragment = new LoginFragment();
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.container, fragment);
                ft.commit();
            }
        }
    }

    ...

    public Session getActiveSession() {
        return Session.getActiveSession();
    }

    public boolean sessionClosed() {
        return session.isClosed();
    }

}

And this is my attempt to test it: 这是我尝试测试它:

@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {

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

    @Before
    public void setup() throws Exception {
        controller = Robolectric.buildActivity(MainActivity.class);
        activity = (MainActivity) controller.get();
    }

    ...

    @Test
    public void testShowLoginWhenSessionClosed() throws Exception {
        Session session = new Session(Robolectric.application);
        spy = Mockito.spy(activity);

        Mockito.doReturn(session).when(spy).getActiveSession();
        Mockito.doReturn(true).when(spy).sessionClosed();

        spy.onCreate(null);

        Mockito.verify(spy).getActiveSession();

        Fragment fragment = 
            spy.getSupportFragmentManager().findFragmentById(R.id.container);
        Assert.assertTrue(fragment instanceof LoginFragment);

    }
}

However, when the test calls spy.onCreate(null) i get the following exception: 但是,当测试调用spy.onCreate(null)我得到以下异常:

java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:4492)
at android.view.LayoutInflater.from(LayoutInflater.java:211)
at org.robolectric.shadows.ShadowActivity.getLayoutInflater(ShadowActivity.java:148)
at android.app.Activity.getLayoutInflater(Activity.java)
at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:110)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

And of course, if I don't call it, the Verify() fails because onCreate is no executed. 当然,如果我不调用它,则Verify()失败,因为onCreate没有被执行。 So, Is this the right way to do it? 那么,这是正确的方法吗? how could spy an Activity using Mockito and drive it through its lifecycle? 怎么可以使用Mockito监视一个Activity并在其生命周期中驱动它?

There might be two solutions. 可能有两种解决方案。

One: 一:

In setup() method, replace controller = Robolectric.buildActivity(MainActivity.class).attach(); setup()方法中,替换controller = Robolectric.buildActivity(MainActivity.class).attach(); instead of controller = Robolectric.buildActivity(MainActivity.class); 而不是controller = Robolectric.buildActivity(MainActivity.class);


The other: 另一个:

First, you should spy the activity correctly. 首先,你应该正确监视活动。 See my answer for spying a activity with robolectric in another post 请参阅我在另一篇文章中使用robolectric监视活动的答案

Second, do not call onCreate() directly on spied activity, you should call ActivityController 's create() , in your case, call controller.create() instead of spy.onCreate(null); 其次,不要直接在spied活动上调用onCreate() ,你应该调用ActivityControllercreate() ,在你的情况下,调用controller.create()而不是spy.onCreate(null);

With Robolectric you have to call controller.create(); 使用Robolectric,你必须调用controller.create(); to start the activity. 开始活动。 After that it should work. 之后它应该工作。

You just need call setup() before get(): 你只需要在get()之前调用setup():

controller.setup();

And if the controller instance is unnecessary, I highly recommend you to get Activity by following code: 如果控制器实例是不必要的,我强烈建议您通过以下代码获取Activity:

activity = Roblectric.setupActivity(MainActivity.class);

As we can see, the difference between these API is setup() and then get(): 我们可以看到,这些API之间的区别是setup()然后是get():

  public static <T extends Activity> ActivityController<T> buildActivity(Class<T> activityClass) {
    return ActivityController.of(shadowsAdapter, activityClass);
  }

  public static <T extends Activity> T setupActivity(Class<T> activityClass) {
    return ActivityController.of(shadowsAdapter, activityClass).setup().get();
  }

So the reason of your crash is setup(): 因此崩溃的原因是setup():

  public ActivityController<T> setup() {
    return create().start().postCreate(null).resume().visible();
  }

it's a mock lifecycle, isn't it? 这是一个模拟生命周期,不是吗?

Finally hope this help you and someone else also need it. 最后希望这有助于你和其他人也需要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM