読者です 読者をやめる 読者になる 読者になる

ほげほげ(仮)

仮死状態

SharedPreferencesをテストする

Android

SharedPreferencesをテストしたときのメモです。

テスト対象コードサンプル

サンプルとしてボタン押したらSharedPreferencesに保存するだけのコードです。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = (Button) findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                SharedPreferences pref = PreferenceManager
                        .getDefaultSharedPreferences(MainActivity.this);
                Editor editor = pref.edit();
                editor.putInt("key", 1);
                editor.commit();

            }
        });
    }

}

テストコード

先ほどのActivityでボタンが押されたらSharedPreferencesに正しく保存されているかを確認するテストコードです。

public class MainActivityTest extends ActivityUnitTestCase<MainActivity> {

    private Button mButton;

    public MainActivityTest() {
        super(MainActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        // Contextの差し替え
        setActivityContext(new TestContext());

        startActivity(new Intent(), null, null);
        MainActivity activity = getActivity();
        mButton = (Button) activity.findViewById(R.id.btn);

        // Preferenceクリア
        clearPreferences();
    }

    private void clearPreferences() {
        SharedPreferences pref = PreferenceManager
                .getDefaultSharedPreferences(getActivity());
        Editor editor = pref.edit();
        editor.clear();
        editor.commit();
    }

    @UiThreadTest
    public void testPutPreferences() throws Exception {

        mButton.performClick();

        SharedPreferences pref = PreferenceManager
                .getDefaultSharedPreferences(getActivity());
        int actual = pref.getInt("key", 0);

        assertEquals(1, actual);
    }

    /**
     * Contextのモック
     *
     */
    class TestContext extends ContextWrapper {

        private static final String PREFIX = "test_";

        public TestContext() {
            super(getInstrumentation().getTargetContext());
        }

        @Override
        public SharedPreferences getSharedPreferences(String name, int mode) {
            // PREFIXを付与してアプリと共有されないようにする
            return super.getSharedPreferences(PREFIX + name, mode);
        }

    }

}
ActivityUnitTestCase

ActivityUnitTestCaseはググれば解説は出てきますが、Activityの単体テストを行うものです。

Contextのモック作成(48行目付近)

ContextWrapperを継承したモックを作成しています。
なぜContextのモックを作成するかというと、SharedPreferencesが実際のアプリと共有されないようにです。
共有されてしまうとアプリを動かした時に影響が出ますし、逆にアプリ側の設定値によってテストが通らなくなる可能性があるためです。
ここではgetSharedPreferencesをオーバーライドしてPREFIXを付与したnameのSharedPreferencesを取得するようにしています。

setActivityContext(14行目付近)

このメソッドでContextをモックに差し替えています。
これはstartActivityの前に呼ぶ必要があります。

Preferencesのクリア(21行目付近)

テスト実行後にSharedPreferencesの値は保持されてしまうので次回実行時に影響がでないように毎回setUpでクリアしています。

AndroidTestCaseの場合のContextモックについて

AndroidTestCaseを使う場合のモックについてはMockContextを継承します。
MockContextはオーバーライドされてないメソッドが使用されるとUnsupportedOperationExceptionが発生するのでgetPackageNameもオーバーライドしています。

    class TestContext extends MockContext {

        private static final String PREFIX = "test_";

        @Override
        public String getPackageName() {
            return getContext().getPackageName();
        }

        @Override
        public SharedPreferences getSharedPreferences(String name, int mode) {
            return getContext().getSharedPreferences(PREFIX + name, mode);
        }
    }


こんな感じで良いのかな…