Reputation: 2792
This my second question related to 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.
I don't know how to drive the spied Activity through its lifecycle in order to call 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:
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. So, Is this the right way to do it? how could spy an Activity
using Mockito
and drive it through its lifecycle?
Upvotes: 4
Views: 4879
Reputation: 2802
There might be two solutions.
One:
In setup()
method, replace controller = Robolectric.buildActivity(MainActivity.class).attach();
instead of 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
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);
Upvotes: 3
Reputation: 1643
You just need call setup() before get():
controller.setup();
And if the controller instance is unnecessary, I highly recommend you to get Activity by following code:
activity = Roblectric.setupActivity(MainActivity.class);
As we can see, the difference between these API is setup() and then 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():
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.
Upvotes: 0
Reputation: 627
With Robolectric you have to call controller.create();
to start the activity. After that it should work.
Upvotes: 0