Flutter-テスト時のSharedPreferences取扱い注意点

SharedPreferencesを使っているメソッドのテストでどうしてもデータが取得できなかった件について。

  • 2022/07/14
    SharedPreferencesがすでに設定されていた場合の追記

テスト時の使用法

テスト対象でSharedPreferencesからデータを受け取っている場合、テストデータ作成時にはSharedPreferences.setMockInitialValuesを使い初期化するようにする。

上記関数はSharedPreferences.instanceで取り出すSharedPreferences用のSingletonのオブジェクトをInMemorySharedPreferencesStore(たぶんオンメモリデータで格納されたもの)を使用することにより、他のテストと設定データの競合をなくすような仕組みなのだと思う。

SharedPreferences.setMockInitialValuesの説明には、パラメータがMap<String, dynamic>を初期データとして渡すという書き方があったのだけど、検索したテスト実装の多くではSharedPreferences.setMockInitialValues({})でからのデータを設定する形で、その後に普通の実装の様にset~を使ってテストデータを設定するような形をとっていた。

多分、データ設定等は別途関数化したものを呼び出すようにした方が効率がいいとかそういう理由なのだろう。

2022/07/14 以下追記

SharedPreferences.setMockInitialValuesでの初期設定だけでは想定した動作にならないケースがあった。

setMockInitialValuesで初期化をしない状態で値を1度でも値を設定してしまった場合。

この場合、ローカル内にKey Valueの情報が保存されてしまい、setMockInitialValuesで初期化した情報にアドオンした形でローカルのKey Valueの情報を取り出せてしまう。

そのため、テストで使用する場合は以下の様な実装にした方がより安全。

final prefs = await SharedPreferences.getInstance();
prefs.clear();
SharedPreferences.setMockInitialValues({});

今回の問題点

Unit Testの呼び出し側でSharedPreferences.setMockInitialValuesで初期値を設定したのだけど、評価対象関数内のSharedPreferences.get~でデータを取り出そうとしても、そのようなデータは無いと怒られてしまった。

しらべたところ以下の様なものがあった。

Flutter SharedPreference do not persist
I want to save user preferences using Flutter's SharedPreference. But the registered preferences are ALL null at new sta...

どうやらSharedPreferences.instanceが初期化されるケースがあるようなのだ。

評価対象関数内の頭で以下のコードを書いている。

DartPluginRegistrant.ensureInitialized();

バックグラウンドでタイマーを動かそうと思い、そのバックグラウンド側の関数が評価対象で、バックグラウンドの初期処理でDart/Flutter関連のパッケージを動かすための初期化処理として記述している。

どうやらこの関数内でSharedPreferences.instanceの初期化が行われていたようで、この実装を外すことでデータの取得はうまくいくことが分かった。

ただ上記の実装は外せないので、今回の対応としては、SharedPreferencesからのデータ取り出しが終了したのちにDartPluginRegistrant.ensureInitialized()を呼び出すという対策で逃げることにした。

コメント

タイトルとURLをコピーしました