DEV Community

Cover image for Improve Android unit tests with shared preferences mock library
Ivan Shafran
Ivan Shafran

Posted on • Updated on

Improve Android unit tests with shared preferences mock library

TL;DR: Shared preferences mock is the lightweight library let you increase coverage of unit tests and simplify code for them with one line of code.

The problem

Unit test on Android uses a framework mock where every method throws UnsupportedOperationExceptionor does nothing depending on your settings in Gradle testOptions.

In unit tests, we mostly test business logic, which often depends on preferences. Therefore you should mock all classes which use SharedPreferencesinside. It is a lot of boilerplate in tests. Moreover, because of this limitation, we never test preferences class code. However, it also may have bugs.

The solution

The library implements SharedPreferences, Context.getSharedPreferences and Context.deleteSharedPreferences in memory using only Java API.

It allows you to use classes with shared preferences in unit tests as is and also to write tests for them.

Usage

Add it in your root build.gradle at the end of repositories:

allprojects {
    repositories {
        ...
        mavenCentral()
    }
}
Enter fullscreen mode Exit fullscreen mode

Add the dependency to module build.gradle:

dependencies {
    testImplementation 'io.github.ivanshafran:shared-preferences-mock:1.2.4'
}
Enter fullscreen mode Exit fullscreen mode

In most cases, preference class or preference utils depends on Context. In unit test instead of real Context pass Context created by new SPMockBuilder().createContext().

If you already have Context with some mocked methods, you can use new SPMockBuilder().wrapContext(preconfiguredContext).

If you need raw SharedPreferences use new SPMockBuilder().createSharedPreferences().

If thread safety is necessary for your test, then configure SPMockBuilder.setThreadSafe(true). It is false by default.

Sample

The sample below describes common code where logic uses preference class to check condition. In line 29 SPMockBuilder creates a context for the preference unit tests. Simple, isn’t it?

public class CounterPreferences {
    // ...
    private final SharedPreferences sharedPreferences;
    public CounterPreferences(@NonNull final Context context) {
        sharedPreferences = context.getSharedPreferences(FILENAME, Context.MODE_PRIVATE);
    }

    public int getCounter() {
        return sharedPreferences.getInt(KEY, 0);
    }
    // ...
}

public class ShowMessageLogic {
    // ...
    public boolean shouldShowMessage() {
        return counterPreferences.getCounter() >= 42;
    }
}

public class ShowMessageLogicTest {

    private final SPMockBuilder spMockBuilder = new SPMockBuilder();
    private CounterPreferences counterPreferences;
    private ShowMessageLogic showMessageLogic;

    @Before
    public void setUp() {
        counterPreferences = new CounterPreferences(spMockBuilder.createContext());
        showMessageLogic = new ShowMessageLogic(counterPreferences);
    }

    @Test
    public void on42CounterItShouldShowMessage() {
        counterPreferences.setCounter(42);
        Assert.assertTrue(showMessageLogic.shouldShowMessage());
    }

    @Test
    public void onLessThan42ItShouldNotShowMessage() {
        counterPreferences.setCounter(41);
        Assert.assertFalse(showMessageLogic.shouldShowMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

Alternatives

Create CounterPreferences interface and implement Java version for a test by yourself:

  • Doesn’t test CounterPreferences implementation
  • Requires boilerplate code in tests

Use Mockito:

  • Doesn’t test CounterPreferences implementation

Use Robolectric:

  • Has test startup delay for a few seconds

Use instrumented test(not a unit test!):

  • Requires device for testing

The library and sample code

You can star the library and learn more info at:

GitHub logo IvanShafran / shared-preferences-mock

Library for unit testing shared preferences classes on Android

Shared Preferences Mock

Build codecov Maven Central

Shared preferences mock is a lightweight library that lets you increase coverage of unit tests and simplify code for them with one line of code.

Motivation

Unit test on Android uses a framework mock where every method throws UnsupportedOperationException or does nothing depending on your settings in Gradle testOptions.

In unit tests, we mostly test business logic, which often depends on preferences. Therefore you should mock all classes which use SharedPreferences inside. It is a lot of boilerplate in tests. Moreover, because of this limitation, we never test preferences class code. However, it also may have bugs.

Under the hood

Under the hood the library implements SharedPreferences, Context.getSharedPreferences and Context.deleteSharedPreferences in memory using only Java API. Check the differences in the differences paragraph.

Download

Important: changed since 1.2.0

Add it in your root build.gradle at the end of repositories:

allprojects {
    repositories {
        mavenCentral()
    }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)