[基礎知識]flutter_test による単体テスト例

1.単体テスト

1-1.テストケース概要:

このテストは、useEffect フックがストリームの変化を正しく捉えて、ウィジェットの状態(この場合は表示されるテキスト)を適切に更新するかを検証しています。
useState で初期状態を設定し、useEffect でその状態がストリームのデータによって更新される流れをテストしています。
StreamController を使うことで、テスト中に任意のタイミングでストリームにデータを送信することが可能です。

1-2.テスト用ファイル環境:

(テスト用フォルダ構成)
¥Flutterプロジェクトフォルダ
|---¥test
   |(1)stream_tests_main.dart
   |(2)run_group_tests_stream.dart

1-3.テスト用ファイル構成:

(1)stream_tests_main.dart(テスト用エントリーポイント):
// ファイル: test/stream_test_main.dart

import 'run_group_tests_stream.dart';

void main() {
  runGroupTestsStream();  //正しい関数を呼び出す
}
(2)run_group_tests_stream.dart(テスト対象ウィジェットのテストケース):
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_test/flutter_test.dart';

//テストケースをグループ化するための関数を定義
void runGroupTestsStream() {
  group('Stream useEffect Test', () {
    //ストリームを制御するための StreamController を宣言
    StreamController<String> streamController = StreamController<String>();

    setUp(() {
      //各テストの前に StreamController を新たに初期化
      streamController = StreamController<String>();
    });

    tearDown(() {
      //テストの後処理として StreamController を閉じる
      streamController.close();
    });

    testWidgets('Stream changes trigger useEffect', (WidgetTester tester) async {
      //テスト対象のウィジェットを構築
      await tester.pumpWidget(
        HookBuilder(
          builder: (context) {
            //useState で初期状態を設定
            final stream = useState<String>("initial");
            //useEffect フックを用いてストリームの値を状態として保持
            useEffect(() {
              final subscription = streamController.stream.listen((data) {
                stream.value = data;
              });
              //ウィジェットが破棄されるときに購読を解除
              return subscription.cancel;
            }, [streamController.stream]);

            return MaterialApp(
              home: Scaffold(
                //表示されるテキストはストリームの現在の値
                body: Text(stream.value),
              ),
            );
          },
        ),
      );

      //初期状態のテキストが表示されることを確認
      expect(find.text("initial"), findsOneWidget);

      //ストリームに新たなデータを送信し、ウィジェットを更新
      streamController.add("new data");
      //ウィジェットの再描画をトリガー
      await tester.pump();

      //新しいデータに更新されたテキストが表示されることを確認
      expect(find.text("new data"), findsOneWidget);
    });
  });
}

1-4.テストケース詳細:

上記のテストコードでは、ストリームの値が変化しています。具体的には、初期値として “initial” が設定された後、テスト中に “new data” という新しいデータがストリームに送信されています。これにより、ストリームの購読が機能しているか、そして useEffect がこの変化にどの様に反応してウィジェットの状態(ここでは表示されるテキスト)を更新するか、を検証しています。

useEffect は依存配列(streamController.strem)に指定された値に基づいて動作します。依存配列の値に変更があった場合にのみ、useEffect のコールバックが再実行され、設定された状態を更新することが期待されます。

このテスト設計により、実際のアプリケーションで useEffect を用いた動的なデータの取り扱いが正しく行われているか、を検証します。

(1)初期設定:

・ useState を使用して、stream の初期値を “initial” として設定します。

・ useEffect フック内で streamController.stream.listen を使い、ストリームからのデータを監視します。

(2)ストリーム(stream)の更新:

・ テスト中に streamController.add(“new data”); を実行しています。
  これにより、streamController が管理するストリームに “new data” という新しいデータが送信されます。

(3)ウィジェットの反応確認:

・ await tester.pump(); が呼ばれると、フレームワークはウィジェットツリーの再構築を行います。これにより、useEffect によって設定されたリスナーが新しいストリームのデータを検出し、useState で管理されている状態が更新されます。

・ その結果、ウィジェットが新しいデータを表示するようになり、expect(find.text(“new data”), findsOneWidget); でその変化を確認しています。

1-5.テスト実行/結果

(一括)
flutter test //実行
00:08 +1: All tests passed! //結果
(個別)
flutter test test/stream_test_main.dart //実行
00:08 +1: All tests passed! //結果

コメントを残す