· android

Learning Android: Robolectric - Testing details got saved to SharedPreferences

I’ve been writing some tests around an app I’ve been working on using the Robolectric testing framework and one thing I wanted to do was check that an OAuth token/secret were being saved to the user’s preferences.

The code that saved the preferences looked like this:

public class AuthoriseWithTwitterActivity extends RoboActivity {
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(intent);
        ...
        save("fakeToken", "fakeSecret");
        ...
    }

    private void save(String userKey, String userSecret) {
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        SharedPreferences.Editor editor = settings.edit();
        editor.putString("user_key", userKey);
        editor.putString("user_secret", userSecret);
        editor.commit();
    }
}

This is an outline of what I wanted to do in the test:

@RunWith(InjectedTestRunner.class)
public class AwesomeTest {
    @Test public void shouldSaveOAuthDetails() {
        activity.onCreate(null);

        ShadowIntent shadowIntent = shadowOf(activity).getNextStartedActivity();

        // Get SharedPreferences and check 'fakeToken' and 'fakeSecret' are stored.
    }
}

In Robolectric it’s possible to replace classes with shadow versions of themselves which get used in the test so I first created a shadow version of PreferenceManager:

@Implements(PreferenceManager.class)
public class ShadowPreferenceManager {
    private static SharedPreferences  preferences = new TestSharedPreferences(new HashMap<String, Map<String, Object>>(), "__default__", Context.MODE_PRIVATE);

    @Implementation
    public static SharedPreferences getDefaultSharedPreferences(Context context) {
        return preferences;
    }

    public static void reset() {
        preferences = new TestSharedPreferences(new HashMap<String, Map<String, Object>>(), "__default__", Context.MODE_PRIVATE);
    }
}

I had to make preferences a static variable here so that it’ll retain state. It’s a bit hacky but it’ll do for now.

Then to hook it up I had to change my test to read like this:

@RunWith(InjectedTestRunner.class)
public class AwesomeTest {
    @Test public void shouldSaveOAuthDetails() {
        Robolectric.bindShadowClass(ShadowPreferenceManager.class);
        activity.onCreate(null);

        ShadowIntent shadowIntent = shadowOf(activity).getNextStartedActivity();

        SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
        assertThat(defaultSharedPreferences.getString("user_key", ""), equalTo("fakeToken"));
        assertThat(defaultSharedPreferences.getString("user_secret", ""), equalTo("fakeSecret"));

        ShadowPreferenceManager.reset();
    }
}

The InjectedTestRunner class used here is pretty much like the one in the Robolectric code base.

There is actually a ShadowPreferenceManager in the Robolectric library but it doesn’t seem to store preferences anywhere as far as I can tell so it wasn’t quite what I wanted.

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket