2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Android】Jetpack DataStoreの単体テストをサクッと行ってみた

Posted at

はじめに

皆さん、ごきげんよう!れぶです!

今回の記事では、SharedPreferencesの代替策であるJetpack DataStoreに関して、基本的な単体テストの手順を整理します。

Preference DataStore(以降、DataStore)を用いた値の読み書きを単体テストレベルで検証したい方に特に参考になればと思います。それでは、参りましょう!!

開発環境

  • MacBook Air
  • Android Studio Dolphin | 2021.3.1
  • Kotlin
  • compileSdkVersion 33
  • targetSdkVersion 33
  • minSdkVersion 21
  • Jetpack DataStore 1.1.0-alpha01

前提

Boolean値を読み書きするDataStoreを対象とします。saveLaunch()の呼び出し前後で、保存された値が正しく変更できているかをテストします。

LaunchDataStore.kt
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
    name = "preferences"
)

//DataStoreの設定
class LaunchDataStore(private val dataStore: DataStore<Preferences>) {
    suspend fun saveLaunch() {
        this.dataStore.edit {
            it[PreferenceKeys.LAUNCH] = true
        }
    }
    val preferenceFlow: Flow<Boolean> =
        dataStore.data
            .catch { exception ->
                if (exception is IOException) {
                    emit(emptyPreferences())
                } else {
                    throw exception
                }
            }.map {
                it[PreferenceKeys.LAUNCH] ?: false
            }
}

private object PreferenceKeys {
    val LAUNCH = booleanPreferencesKey("isLaunch")
}

テスト手順

1. 依存関係の追加

build.gradle
    //インストゥルメント化単体テスト用
    androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test:rules:1.1.0'
    //コルーチンの単体テスト用
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"

適宜最新バージョンに合わせてください。

2. テストクラスの作成

今回はエミュレータで実行する単体テストであるため、src/androidTest/java内にテストクラスを作成します。以降の手順に関しては、このクラスに記述します。

src/test/java内で作成したクラスでテストしても上手く実行できないため、ご注意ください。

3. DataStoreインスタンスの生成

まずPreferenceDataStoreFactory.create()でDataStoreのインスタンスを生成します。その際に必要な引数は、事前に定義しておきます。

今回はLaunchDataStoreクラス内でDataStoreの読み書きを記述しているため、LaunchDataStoreインスタンスも生成します。

DataStoreUnitInstrumentedTest.kt
    private val TEST_DATASTORE_NAME = "preferences"
    private val dispatcher = UnconfinedTestDispatcher()
    private val context: Context = 
        InstrumentationRegistry.getInstrumentation().targetContext
    private val scope = TestScope(dispatcher + Job())
    private val dataStore: DataStore<Preferences> =
        PreferenceDataStoreFactory.create(
            scope = scope,
            produceFile = { context.preferencesDataStoreFile(TEST_DATASTORE_NAME) }
        )
    private val launchDataStore = LaunchDataStore(dataStore)

4. テスト前処理の設定

DataStoreの読み書きはコルーチンを元に非同期で処理されるため、テスト前にDispatchers.setMainを用いてMainDispatcherTestDispatcherに置き換える必要があります。

また、念のためDataStoreで保存されるデータをクリアにするため、DataStoreファイル全体を削除します。複数回テストを繰り返した場合に、There are multiple DataStores active for the same file.と怒られないように対策しています。

DataStoreUnitInstrumentedTest.kt
    @Before
    fun setup() {
        //データを毎回新規にするためにファイル全削除
        context.run {
            File(filesDir, "datastore").deleteRecursively()
        }
        Dispatchers.setMain(dispatcher)
    }

5. テスト後処理の設定

テスト終了後は、DispatcherとTestScopeをきちんとリセットしてあげましょう。

DataStoreUnitInstrumentedTest.kt
    @After
    fun tearDown() {
        Dispatchers.resetMain()
        scope.cancel()
    }

6. 書き込み前後のデータをテスト

さていよいよテスト本番です。非同期処理のため、runTestで囲みます。

デフォルトではfalseが返ってきて、launchDataStore.saveLaunch()の実行後はtrueが返ってくればテスト大成功です。

DataStoreUnitInstrumentedTest.kt
    @Test
    fun validateIsTrue() {
        scope.runTest {
            assertEquals(false,launchDataStore.preferenceFlow.firstOrNull())
            //trueに変更
            launchDataStore.saveLaunch()
            assertEquals(true,launchDataStore.preferenceFlow.firstOrNull())
        }
    }

全コード

おわりに

今回はJetpack Preference DataStoreの単体テスト方法をサクッとまとめました。DataStoreはコルーチンを使用しているため、コルーチンを用いたテスト方法(「参考サイト」に記載)が理解できていれば簡単に行えるのかなと実際やってみて感じました。

上記のやり方を応用してより複雑なDataStoreの単体テストも実現できると思うので、この記事が少しでも役立つと嬉しいです。以上です。ありがとうございました!

参考サイト

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?