93045


WidgetTest時に、更新されたはずの値が更新されず、悩んでいます。

以下のTrialLogicクラスのaddメソッドを使って_numの値を更新し、

[code]

    class TrialLogic with ChangeNotifier {
      late int _num;
    
      int get num {
        return _num;
      }
    
      void add(a, b) {
        _num = a + b;
        notifyListeners();
      }
    }
    
[/code]

更新した値が以下のTrialWidgetクラスに表示されていることを確認するテストをしたいのですが、

[code]

    class TrialWidget extends StatelessWidget {
      const TrialWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        final trialLogic = Provider.of<TrialLogic>(context);
        Future(() => trialLogic.add(5, 10));
        return Text(trialLogic.num.toString());
      }
    }
    
[/code]

以下のようにテストを書いて実行したところ、

[code]

    testWidgets('更新した値が表示されていることを確認', (widgetTester) async {
      await widgetTester.pumpWidget(
        ChangeNotifierProvider(
          create: (_) => TrialLogic(),
          child: MaterialApp(
            home: TrialWidget(),
          ),
        ),
      );
      await widgetTester.pump();
    
      expect(find.text('15'), findsOneWidget);
    });
    
[/code]

以下のエラーが発生しました。値が更新されていないようです。  
[_InheritedProviderScope<TrialLogic?>]):  
LateInitializationError: Field '_num@22387026' has not been initialized.

しかしながら、シミュレータで確認してみると、更新された値が問題なく表示されていました。

テストではFutureで囲まれた処理を待たずにテストが走ってしまうため、  
Futureで囲まれた処理を待つ場合にはexpectの前にawait pumpEventQueue()を挟まないといけないと聞いたので、  
実際にやってみたのですが、今度はテストが一向に終わらなくなってしまいました。  
他にFutureで囲まれた処理を待つ方法がわからなかったので、教えてください。  
また、その他にも問題点がありましたら、ご指摘いただければ幸いです。


CC BY-SA 4.0
2022-12-27T07:43:05.743
93040
2022-12-27T11:48:57.463
56244
question
flutter dart
WidgetTestにてFutureで囲まれた処理を待つ方法を教えてください


TrialLogicとTrialWidgetの設計に問題があると思われます。  
TrialLogicでは_numがlate指定されていて、その決定はaddで行われます。  
これに対してTrialWidget内でTrialLogicのaddをFutureで実施しているので、その次の行でのgetではまだ_numが確定されていません。そのため提示されているエラーが出るのは当然です。

TrialLogicではlateではなく、初期値を設定する。  
TrialWidget内でaddメソッドを呼び出すのではなく、通常こういうのは他の場所でaddが呼び出され、その結果を表示するというのではないでしょうか。

正しく動く実装としては以下の様な感じかな。

[code]

    class TrialLogic with ChangeNotifier {
      int _num = 0;
    
      int get num {
        return _num;
      }
    
      void add(a, b) {
        _num = a + b;
        notifyListeners();
      }
    }
    
    class TrialWidget extends StatelessWidget {
      const TrialWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        final trialLogic = Provider.of<TrialLogic>(context);
        return Text(trialLogic.num.toString());
      }
    }
    
[/code]

テスト部分

[code]

      testWidgets('更新した値が表示されていることを確認', (widgetTester) async {
        final data = TrialLogic();
        final widget = ChangeNotifierProvider(
          create: (_) => data,
          child: const MaterialApp(
            home: TrialWidget(),
          ),
        );
        await widgetTester.pumpWidget(widget);
        data.add(5, 10);
        await widgetTester.pump();
    
        expect(find.text('15'), findsOneWidget);
      });
    
[/code]

もし非同期でのデータ確定でその結果を表示したいのであれば、FutureBuilderを使うなどして、未決定の状態を管理してウィジェットを表示するようにする必要があります。

またシミュレーター？の方ではaddメソッドをTrialWidgetのbuild呼び出し前に実行しているので_numが確定しているので正しく表示されているのでは。  
そうなのであれば、シミュレーター処理手順を条件としたテストとするべきです。


CC BY-SA 4.0
2022-12-27T11:48:57.463
93045
2022-12-27T11:48:57.463
54446
93040
answer