【Flutter】pumpAndSettleメソッドのまとめと使い方

Flutter基礎

flutterでテストしていて理解を深めたいポイントをまとめています。
今回はpumpAndSettleメソッドについてまとめました。

公式

pumpAndSettle method - WidgetTester class - flutter_test library - Dart API
API docs for the pumpAndSettle method from the WidgetTester class, for the Dart programming language.

概要

pumpAndSettleメソッドとは

  • pumpメソッドを繰り返し実行するメソッド
  • 特徴
    • フレームがスケジュールされていなくても1回は必ず呼ばれる
    • 全てのアニメーションが完了を促す

フレームがスケジュールされるとは

  • 次回のフレーム処理(UI 更新)をキューに積む状態

「フレームがスケジュールされていない」状態は

これは逆に言えば、

  • アニメーションもしていない
  • 状態も更新されていない
  • ユーザー操作による描画要求もない

という静止状態です。

普通はこの場合、新しいフレームは不要なので何もスケジュールされません。

pumpAndSetteとフレームのスケジュールの関係

  • pupmAndSettleはフレームがスケジュールされていなくても一回は呼ばれる
  • その後、「もうフレームが必要ない状態になるまで」繰り返す。 → つまり、スケジュールされたフレームがゼロになるまで待つ。
状態更新 (setStateなど) → フレームスケジュール → pumpで描画 → settle判定
何もない静止状態         → (フレームなし)  → pumpAndSettleが1回pumpして終了

参考例

内容

  • ログイン済みかどうかでWidgetを出し分けている(Firebase)
  • 未ログインの時に LogInウィジェットを表示できているかテスト

全体のソースコード

  testWidgets('未ログインならLogInを表示', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          authStateProvider.overrideWith((ref) => Stream.value(null)),
        ],
        child: const MaterialApp(home: App()),
      ),
    );

    // ビルドが終わるまで呼び続ける
    await tester.pumpAndSettle();

    expect(find.byType(LogIn), findsOneWidget);
  });

pumpAndSettleの使い方

  • authStateProviderというUserの状態を監視するProviderをpumpWidgetしている
  • 何も定義がないとUIが更新されずLogInウィジェットは見つからない
  • pumpWidgetだとDurationをStreamが完了するまでの秒数与えないといけないが不透明でわかりにくい
  • pumpAndSettleで描画が終わるまでpumpし続けることでUIの更新が完了する
    • その後 expectでLogInメソッドを検知できる

pumpAndSettle シーケンス図

Tester             WidgetTree              EventLoop               SchedulerBinding
 |                     |                        |                           |
 | pumpAndSettle()     |                        |                           |
 |-------------------->|                        |                           |
 | pump()              |                        |                           |
 |-------------------->|                        |                           |
 |                     | flush microtasks       |                           |
 |                     |----------------------->|                           |
 |                     |   authStateProviderのStreamイベント処理            |
 |                     |<-----------------------|                           |
 |                     | setState()             |                           |
 |                     |------------------------| scheduleFrame()           |
 |                     |                        |-------------------------->|
 |                     |                        |      hasScheduledFrame = true
 |                     |                        |<--------------------------|
 | pump 2nd frame      |                        |                           |
 |-------------------->|                        |                           |
 |                     | Rebuild UI             |                           |
 |                     |------------------------|                           |
 |                     | 完了 → フレームなし    |                           |
 |                     |                        | hasScheduledFrame = false |
 | pumpAndSettle終了   |                        |                           |


解説

  1. 最初の pump
    • pumpAndSettle は必ず最初に 1 回 pump して、保留中のマイクロタスクを flush(全実行)。
    • この時点で authStateProviderStream.value(null) のイベントが処理される。
  2. マイクロタスク内でフレームスケジュール
    • Stream の購読処理で setState が呼ばれる。
    • setStateSchedulerBinding.scheduleFrame() により hasScheduledFrame = true になる。
  3. 次のフレーム描画
    • pumpAndSettle が「まだフレームが必要だ」と判断し、次の pump で UI を再構築。
    • LogIn ウィジェットがツリーに現れる。
  4. フレームがなくなって settle
    • UI が安定(フレームが不要)になったらループ終了。
    • このタイミングで expect(find.byType(LogIn), findsOneWidget) が通る。

まとめ

  • pumpAndSettleは繰り返しフレームを更新
  • フレームがスケジュールされている限り実行する
  • repeatなどでアニメーションを繰り返す場合は注意

簡単ですが、pumpAndSettleについてまとめてみました。ではまた。

コメント

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