6

I have an android application which uses fragments and has implemented ActionBarCompat. I wrote simple Robolectric test shown below:

@Test
public void shouldNotBeNull() throws Exception {
    MainFragment mainFragment = new MainFragment();
    startFragment(mainFragment);
    assertThat(mainFragment, notNullValue());
    assertThat(mainFragment.getActivity(), notNullValue());
}

private void startFragment(MainFragment fragment) {
    FragmentActivity activity = new FragmentActivity();
    shadowOf(activity).callOnCreate(null);
    shadowOf(activity).callOnStart();
    shadowOf(activity).callOnResume();

    FragmentManager fragmentManager = activity.getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.add(fragment, null);
    fragmentTransaction.commit();
}

I am getting following exception:

java.lang.NullPointerException: null
at android.app.Activity.invalidateOptionsMenu(Activity.java:2595)
at android.support.v4.app.ActivityCompatHoneycomb.invalidateOptionsMenu(ActivityCompatHoneycomb.java:30)
at android.support.v4.app.FragmentActivity.supportInvalidateOptionsMenu(FragmentActivity.java:572)
at android.support.v4.app.Fragment.setHasOptionsMenu(Fragment.java:708)
at com.example.android.ui.MainFragment.onCreate(MainFragment.java:599)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:834)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1080)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:622)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)
at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:37)
at org.robolectric.shadows.ShadowLooper.post(ShadowLooper.java:198)
at org.robolectric.shadows.ShadowHandler.postDelayed(ShadowHandler.java:56)
at org.robolectric.shadows.ShadowHandler.post(ShadowHandler.java:51)
at android.os.Handler.post(Handler.java)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1322)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525)
at com.example.android.ui.MainFragmentTest.startFragment(MainFragmentTest.java:36)
at com.example.android.ui.MainFragmentTest.shouldNotBeNull(MainFragmentTest.java:22)

When using something like this:

MainActivity activity = new MainActivity();
shadowOf(activity).callOnCreate(null);
shadowOf(activity).callOnStart();
shadowOf(activity).callOnResume();

where MainActivity is holder activity for MainFragment, I get the following exception:

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at org.robolectric.res.builder.RobolectricPackageManager.getActivityInfo(RobolectricPackageManager.java:59)
at android.support.v7.app.ActionBarActivityDelegate.getUiOptionsFromMetadata(ActionBarActivityDelegate.java:157)
at android.support.v7.app.ActionBarActivityDelegateICS.onCreate(ActionBarActivityDelegateICS.java:53)
at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.java:98)
at com.example.android.ui.MainActivity.onCreate(MainActivity.java:45)
at org.robolectric.shadows.ShadowActivity.invokeReflectively(ShadowActivity.java:176)
at org.robolectric.shadows.ShadowActivity.callOnCreate(ShadowActivity.java:121)
at com.example.android.ui.MainFragmentTest.startFragment(MainFragmentTest.java:28)
at com.example.android.ui.MainFragmentTest.shouldNotBeNull(MainFragmentTest.java:22)

I suspect it could be something about ActionBarCompat and Robolectric not being compatible. Any help would be appreciated.

Nemanja Milkov
  • 256
  • 2
  • 7
  • What does `shadowOf(activity)` return? – Terry Aug 06 '13 at 11:52
  • Thanks for participating. As for explanation of shadowOf method, best one is given on robolectric web site: "Sometimes Android classes don’t provide methods to access the state of the Android objects under test. The Robolectric.shadowOf() methods provide reference to the shadow instances representing Android objects, allowing tests to assert on state otherwise not available". If otherwise you assumed that shadowOf(activity) returns null while debugging, id doesn't. – Nemanja Milkov Aug 06 '13 at 13:34
  • The problem btw still persists, so any suggestion would be helpfull. – Nemanja Milkov Aug 06 '13 at 13:40
  • No, I was wondering what was the return type to see on which object the `callOnCreate(null)` method is executed - maybe callOnCreate with null doesn't work? – Terry Aug 06 '13 at 13:53
  • The return type is ShadowActivity which is fine. The object is not null. As for passing null on callOnCreate, that is also fine, it only means that there isn't any saved bundle to pass to activity. Anyway, the idea for my testing logic can be viewed here [java.lang.IllegalStateException: Activity has been destroyed](http://stackoverflow.com/questions/15568128/java-lang-illegalstateexception-activity-has-been-destroyed) – Nemanja Milkov Aug 06 '13 at 14:08
  • Hey, have you been able to make any progress on this? – dng Aug 22 '13 at 12:38
  • Unfortunately, I haven't found solution for this problem. – Nemanja Milkov Aug 23 '13 at 12:13
  • Try this answer: http://stackoverflow.com/a/12903280/1000837 – Jigish Chawda Sep 21 '13 at 09:12
  • Have you tried to put @Config(reportsdk=10) annoation? – Orhan Obut Jan 19 '14 at 15:46

1 Answers1

0

As of Robolectric 2.4, it is supposed to support the Appcompat library. There are a few gotchas though as it doesn't work out of the box. Things that helped me:

  1. Creating a project.properties file with the following contents

As described in the config manual:

target=android-19 android.library.reference.1=/../../build/intermediates/exploded-aar/com.android.support/appcompat-v7/20.0.0    
android.library.reference.2=/../../build/intermediates/exploded-aar/com.android.support/support-v4/20.0.0
android.library.reference.3=/../../build/intermediates/exploded-aar/com.viewpagerindicator/library/2.4.1
  1. Setting exculdes in build.gradle for Robolectric

Apparently Robolectric has its own versions of the support libraries so the following is needed to prevent possible duplicate dependencies (referenced from here):

   androidTestCompile('org.robolectric:robolectric:2.4') {
    exclude module: 'classworlds'
    exclude module: 'commons-logging'
    exclude module: 'httpclient'
    exclude module: 'maven-artifact'
    exclude module: 'maven-artifact-manager'
    exclude module: 'maven-error-diagnostics'
    exclude module: 'maven-model'
    exclude module: 'maven-project'
    exclude module: 'maven-settings'
    exclude module: 'plexus-container-default'
    exclude module: 'plexus-interpolation'
    exclude module: 'plexus-utils'
    exclude module: 'wagon-file'
    exclude module: 'wagon-http-lightweight'
    exclude module: 'wagon-provider-api'
    exclude group: 'com.android.support', module: 'support-v4'
    exclude group: 'com.android.support', module: 'appcompat-v7' }
p4sh4
  • 3,292
  • 1
  • 20
  • 33