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.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.