【Flutter】Streamのテストの基礎

  • 2024年8月7日
  • 2024年8月7日
  • test

対象者

  • Flutterの非同期処理やストリームのテストに関心があるエンジニア
  • プロジェクトでFlutterを採用しており、ストリームテストの知識を深めたいと考えている人
  • 技術的なスキル向上を目指している学習意欲の高い開発者

はじめに

Flutterを使ってアプリ開発を行っているあなた。非同期処理やStreamの動作に対して不安を感じていませんか?この記事では、DartでStreamの動作を確認できるようになるべく、Streamのテストに関する基礎を分かりやすく解説し、あなたの疑問を解消します。
この記事を読むことで、Streamのテストに関する全体像がつかめ、自信を持ってテストを実装できるようになります。

Streamテストの基礎

ベース

シンプルなストリームのテスト。

  • Stream.fromIterable: イテラブルからストリームを作成
  • emitsInOrder: ストリームが順番に要素を放出することを確認
final stream = Stream.fromIterable([
  'Ready.',
  'Set',
  'Go!',
]);

expect(
  stream,
  emitsInOrder([
    'Ready.',
    'Set',
    'Go!',
  ]),
);

いろんなMatcher

異なるMatcherを使ったストリームのテスト。

  • startsWith: 文字列が特定の文字で始まるかを確認
  • emitsAnyOf: いずれかの要素を放出することを確認
  • emitsDone: ストリームの終了を確認
final stream = Stream.fromIterable([
  'Ready.',
  'Set',
  'Go!',
]);

expect(
  stream,
  emitsInOrder([
    'Ready.',
    startsWith('S'),
    emitsAnyOf(['Go!', 'False Start!']),
    emitsDone,
  ]),
);

addを使ったテスト

StreamControllerを使用して手動でストリームに値を追加するテスト。

  • StreamController: 手動でストリームに値を追加
  • add: ストリームに値を追加
  • emitsInOrder: 順番に要素を放出することを確認
final stream = StreamController<int>();
stream.add(1);
stream.add(2);
stream.close();

expect(
  stream.stream,
  emitsInOrder([1, 2, emitsDone]),
);

expect を前にもかける

expectをストリームに値を追加する前に使用するテスト。

  • StreamController: 手動でストリームに値を追加
  • expect: テストの期待値を設定
final stream = StreamController<int>();
expect(
  stream.stream,
  emitsInOrder([1, 2, emitsDone]),
);

stream.add(1);
stream.add(2);
stream.close();

expectLater

expectLaterを使用して遅延ストリームのテストを行う。

  • StreamController: 手動でストリームに値を追加
  • expectLater: 非同期でストリームの期待値を設定

expectに変えても動作する。違いが分からん(後で検証するよ、という意思表示かな)

final stream = StreamController<int>();
Future<void> addWithDelay(int value) async {
  Future.delayed(const Duration(milliseconds: 10)).then((_) {
    stream.add(value);
  });
}

expectLater(
  stream.stream,
  emitsInOrder([1, 2, emitsDone]),
);

addWithDelay(1);
addWithDelay(2);

// close するまえに、データを入れるため
await Future.delayed(const Duration(milliseconds: 10));
stream.close();

処理の遅い処理 listenを使ってみる

listenを使って遅延ストリームの処理をテストする。

  • StreamController: 手動でストリームに値を追加
  • listen: ストリームの要素をリッスンして処理
  • Completer: 非同期処理の完了を待つためのオブジェクト
final stream = StreamController<int>();
Future<void> addWithDelay(int value) async {
  Future.delayed(const Duration(milliseconds: 10)).then((_) {
    stream.add(value);
  });
}

var completer = Completer<int>();
stream.stream.listen((int data) {
  completer.complete(data);
});

addWithDelay(1);
expect(await completer.future, 1);

completer = Completer<int>();
addWithDelay(2);
expect(await completer.future, 2);

stream.close();

Q&A

Q1: expectexpectLaterの違いは何ですか?

expectは通常の同期的なテストに使用され、expectLaterは非同期処理を伴うテストで使用されます。今回の例ではどちらも同じように動作しますが、非同期処理を扱う際にはexpectLaterを使うのが一般的です。

Q2: emitsInOrderとは何ですか?

emitsInOrderは、ストリームが特定の順序で要素を放出することを確認するMatcherです。複数の要素を順番に放出するストリームの動作をテストするのに便利です。

Q3: StreamControllerとは何ですか?

StreamControllerは、手動でストリームにデータを追加できるコントローラーです。ストリームにデータを追加したり、ストリームを閉じたりするために使用します。

参考

まとめ

本記事では、Flutterでのストリームのテスト方法について紹介しました。基本的なストリームの操作から、さまざまなMatcherを使用したテスト方法、遅延処理を伴うストリームのテスト方法について学びました。これらの知識を活用して、非同期処理を含むアプリケーションのテストを効果的に行いましょう。