Mocking and Testing Shared Preferences in Flutter Unit Tests

Mocking and Testing Shared Preferences in Flutter Unit Tests

Introduction

This article demonstrates how to unit-test Shared Preferences in Flutter projects.

This article assumes that the reader is familiar with Flutter development and the Dart language.

The code in the demo was created using Flutter Channel stable, 2.5.3.

Problem Statement

We have a SharedPreferencesUtil class that makes use of the SharedPreferences object to store and retrieve an integer count. Our task is to unit-test the methods of this class.

The class is shown below:

import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SharedPreferencesUtil {
  SharedPreferencesUtil({required this.sharedPreferences});

  final SharedPreferences sharedPreferences;

  @visibleForTesting
  static const String countKey = 'counter';

  int getCount() {
    return sharedPreferences.getInt(countKey) ?? 0;
  }

  Future<bool> setCount(int count) async {
    return sharedPreferences.setInt(countKey, count);
  }
}

Testing the methods

In the SharedPreferencesUtil class above, the SharedPreferences object is passed through the constructor and it is used in the following methods:

  • getCount(): To return the value of the count integer stored in SharedPreferences with the countKey key and return 0 if the value in SharedPreferences is null
  • setCount(): To set the value of count int with the countKey key in SharedPreferences

In order to write a test, we need to mock the SharedPreferences object that we pass into the SharedPreferencesUtil class.

This is done using the SharedPreferences.setMockInitialValues() static method.

setMockInitialValues()

Initializes the shared preferences with mock values for testing.

Source

This method is used to mock the initial state of the SharedPreferences object used in tests. It takes a parameter of type Map<String, Object> for which the key is used to identify the stored SharedPreferences object and the value is the actual object stored in SharedPreferences.

For instance:

If we want our SharedPreferences object in our test to store the number 42 with the key counter, we do it this way:

SharedPreferences.setMockInitialValues({'counter': 42});

Testing the getCounter() method

  • Test that the getCount() method returns 0 if there is no value stored in SharedPreferences.

    We first call the SharedPreferences.setMockInitialValues() and pass it {} (empty Map object) method to make sure nothing is stored in SharedPreferences. We, then, pass it into the SharedPreferencesUtil class.

    We, then, can call the getCount() method and compare it with the expected value of 0 using the expect() method from the test library.

import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_unit_tests_flutter/shared_preferences_util.dart';
import 'package:test/test.dart';

main() {
  group(SharedPreferencesUtil, () {
    group('getCounter', () {
      test('returns 0 if no value is stored in SharedPreferences', () async {
        SharedPreferences.setMockInitialValues({});

        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);

        const expectedCounter = 0;
        final actualCounter = sharedPreferencesUtil.getCount();

        expect(expectedCounter, actualCounter);
      });
    });
  });
}
  • Test that the getCount() method returns the correct value stored in SharedPreferences.

    We first call SharedPreferences.setMockInitialValues() and pass it {SharedPreferencesUtil.countKey: counterValue} where SharedPreferencesUtil.counterKey is the key and counterValue contains the value we want to store. We, then, pass it into the SharedPreferencesUtil class.

    We, then, can call the getCount() method and compare it with the expected value of 0 using the expect() method.

import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_unit_tests_flutter/shared_preferences_util.dart';
import 'package:test/test.dart';

main() {
  group(SharedPreferencesUtil, () {
    group('getCounter', () {
      test('returns 0 if no value is stored in SharedPreferences', () async {
       ...
      });

      test('returns the correct value stored in SharedPreferences', () async {
        const counterValue = 42;
        SharedPreferences.setMockInitialValues(
            {SharedPreferencesUtil.countKey: counterValue});
        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);

        const expectedCount = counterValue;
        final actualCounter = sharedPreferencesUtil.getCount();
        expect(expectedCount, actualCounter);
      });
    });
  });
}

Testing the setCounter() method

  • Test that the setCount() method stores the correct value in SharedPreferences.

    We first call the SharedPreferences.setMockInitialValues() and pass it {} (empty Map object) method to make sure nothing is stored in SharedPreferences. We, then, pass it into the SharedPreferencesUtil class.

    We, then, can call the SharedPreferences.getInt() method, pass the SharedPreferencesUtil.countKey key to it to get the value in SharedPreferences compare it with the expected value in the countValue variable.

import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_unit_tests_flutter/shared_preferences_util.dart';
import 'package:test/test.dart';

main() {
  group(SharedPreferencesUtil, () {
    group('getCounter', () {
      test('returns 0 if no value is stored in SharedPreferences', () async {
        ...
      });

      test('returns the correct value stored in SharedPreferences', () async {
        ...
      });
    });

    group('setCounter', () {
      test('stores the correct count value in SharedPreferences', () async {
        SharedPreferences.setMockInitialValues({});
        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);
        const countValue = 42;

        sharedPreferencesUtil.setCount(countValue);
        const expectedCounter = countValue;
        final actualCounter =
            sharedPreferences.getInt(SharedPreferencesUtil.countKey);

        expect(expectedCounter, actualCounter);
      });
    });
  });
}

Complete Test File

The content of the entire test file is shown below:

import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_unit_tests_flutter/shared_preferences_util.dart';
import 'package:test/test.dart';

main() {
  group(SharedPreferencesUtil, () {
    group('getCounter', () {
      test('returns 0 if no value is stored in SharedPreferences', () async {
        SharedPreferences.setMockInitialValues({});

        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);

        const expectedCounter = 0;
        final actualCounter = sharedPreferencesUtil.getCount();

        expect(expectedCounter, actualCounter);
      });

      test('returns the correct value stored in SharedPreferences', () async {
        const counterValue = 42;
        SharedPreferences.setMockInitialValues(
            {SharedPreferencesUtil.countKey: counterValue});
        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);

        const expectedCount = counterValue;
        final actualCounter = sharedPreferencesUtil.getCount();
        expect(expectedCount, actualCounter);
      });
    });

    group('setCounter', () {
      test('stores the correct count value in SharedPreferences', () async {
        SharedPreferences.setMockInitialValues({});
        final SharedPreferences sharedPreferences =
            await SharedPreferences.getInstance();

        final SharedPreferencesUtil sharedPreferencesUtil =
            SharedPreferencesUtil(sharedPreferences: sharedPreferences);
        const countValue = 42;

        sharedPreferencesUtil.setCount(countValue);
        const expectedCounter = countValue;
        final actualCounter =
            sharedPreferences.getInt(SharedPreferencesUtil.countKey);

        expect(expectedCounter, actualCounter);
      });
    });
  });
}

Conclusion

Mocking the SharedPreferences object in tests makes use of the setMockInitialValues method to initialize the state.

The complete code can be found on GitHub.