Slide 1

Slide 1 text

(Flutterテスト)沼にハマってやってみた

Slide 2

Slide 2 text

自己紹介 室山大輔 株式会社exa 面白法人カヤック 株式会社ゆめみ(イマココ) Android/Flutter

Slide 3

Slide 3 text

NECカシオ Life UX Home/Life UX Lock

Slide 4

Slide 4 text

スマホゲーマー向けゲームSNS Lobi

Slide 5

Slide 5 text

富士急ハイランド「絶望要塞3」アプリ

Slide 6

Slide 6 text

ゆめみのご紹介

Slide 7

Slide 7 text

https://www.yumemi.co.jp/

Slide 8

Slide 8 text

https://www.yumemi.co.jp/

Slide 9

Slide 9 text

こんなイベントもやります

Slide 10

Slide 10 text

Flutterアプリのテストはどーやる?

Slide 11

Slide 11 text

Flutter におけるテスト(おさらい) unit test A unit test tests a single function, method, or class. widget test A widget test (in other UI frameworks referred to as component test) tests a single widget. integration test An integration test tests a complete app or a large part of an app. Testing & debugging > Testing Flutter apps - https://docs.flutter.dev/testing/overview

Slide 12

Slide 12 text

unit test 単一の関数・メソッド・クラスを対象としたテスト 外部依存は mockito などを用いてモックしたりする ダミーデータは data_fixture_dart や json ファイルを用意することが多い 様々な条件下でのロジックを検証する pub.dev > mockito - https://pub.dev/packages/mockito

Slide 13

Slide 13 text

widget test 単一のウィジェットを対象としたテスト a.k.a component test UIが期待通りに表示されることや、ユーザーインタラクションに応じた検証 golden test もここに含まれる 実際の UI system と比較すると簡略化される 状態変化に応じたリビルドのため WidgetTester# pump を呼んだり、 WidgetTester#pumpAndSettle を呼んだりする pub.dev > golden_toolkit - https://pub.dev/packages/golden_toolkit

Slide 14

Slide 14 text

integration test アプリ全体やアプリの大部分(機能間連携や複数のウィジェットを横断した動 作)を対象としたテスト 実機(エミュレータ・シミュレータ含む)での実行となるため、動作パフォーマ ンスの検証にも役立つ 動作環境(プラットフォーム)に依存した機能についての検証 メディアストレージ 実際に通信を伴う機能

Slide 15

Slide 15 text

テストの重要性と目的 バグの早期発見 どんなに注意していても、人が書く以上間違いは起こる これは仕方ないこと 起こってしまったことを早期に検知できることでダメージを最小限にする 品質の確保 テストコードにより、考慮漏れのパターンを見出しやすくなる 意図に対するテストを行いことによって、外部から見たアプリケーションの 保証が出来る(ブラックボックステスト) テストコードによる実装コードの振る舞いを表すドキュメントとして テストのためのコード品質向上(単一責任の原則を意識するなど)

Slide 16

Slide 16 text

とはいえ… テストカバレッジ100%を目指そう、とはなりません(※) 以下ケースの場合は、その限りではない 一度配布したら更新ができない 不具合が金銭的損害に繋がりかねない 要件次第ということ

Slide 17

Slide 17 text

テストカバレッジ カバレッジが低ければ、ソースコード(テストコード)の品質が低い可能性が高 い カバレッジが高くとも、ソースコードの品質が高いとはいえない カバレッジを 100% に近づけようとする労力と、テストコード(ケース)による バグ検出率は見合っていない 80~85%ぐらいはともかくも、そこから先が大変

Slide 18

Slide 18 text

例の表 Testing & debugging > Testing Flutter apps - https://docs.flutter.dev/testing/overview

Slide 19

Slide 19 text

有用なテスト、冗長なテスト いずれのテストも一定の効果がある テストにかけるコストと、テストによって得られる効果は見合っているか? テストを整備することで達成した目的をはっきりしておかないと、テストのため のテストになってしまいかねない

Slide 20

Slide 20 text

widget test が役立ちそうなとき 通信結果に応じて、表示分岐がある 通信成功時 通信中 通信失敗時 ユーザー操作などに応じた、表示分岐のあるウィジェット UI Stackに基づいたものなど(Ideal, Empty, Error, Partial, Loading) 環境起因の表示分岐(言語、ダークモード、レイアウト倍率) 実機、エミュレータ・シミュレータを使わずに実行され高速なため、頻繁に行い たい検証に有効

Slide 21

Slide 21 text

integration test が効果的な場面 ネイティブ(Android/iOS)APIに依存するテスト OSバージョンによって挙動の異なるAPI(メディアストレージ関連APIなど)の動 作確認などにおいて特に有効 integration test は実行コストが高いため、ここぞというときに使うことが肝要 コード(実装)への依存が少なく、機能要件を担保しやすい リファクタリングや抜本的なアーキテクチャ刷新の助けになる

Slide 22

Slide 22 text

テストの重要性と目的(再掲) バグの早期発見 どんなに注意していても、人が書く以上間違いは起こる これは仕方ないこと 起こってしまったことを早期に検知できることでダメージを最小限にする 品質の確保 テストコードにより、考慮漏れのパターンを見出しやすくなる 意図に対するテストは、実装に依らず意図が実現できているかを保証できる コードの振る舞いを表すドキュメントとして テストのためのコード品質向上(単一責任の原則を意識するなど)

Slide 23

Slide 23 text

テストを効率化するために いずれのテストにおいても、特に integration test などにおいて、テストのメンテナ ンスコストを下げることは重要 テストに役立つパッケージの導入 data_fixture_dart によってダミーデータのパターン生成を簡便化 Riverpod を介したモックオブジェクトによる差し替え given_when_then や Robot パターンによるテストコードの意図と実装の分離 テスト種別ごとに適当と思われるスパンでの自動実行を行う unit < widget < integration <= e2e でテストのメンテナンスコストは高まるが、スコ ープは広がる&コードへの依存度が下がることを理解し活用する 採用プロダクトにおいて、どういったスコープのテストが重要なのか検討し て適用する

Slide 24

Slide 24 text

E2E test への期待 ソフトウェアで最も大切なのは「振る舞い」であり、振る舞いこそがユーザーの 求めるものである。期待される振る舞いを私たちが追加すればユーザーは喜ぶ が、ユーザーの求める振る舞いを変更、あるいは削除してしまえば、バグの作り 込みとなり、私たちへの信頼は失われてしまう。 振る舞いを保証する方法として、E2Eテストは非常に有用 レガシーコード改善ガイド - https://www.shoeisha.co.jp/book/detail/9784798116839

Slide 25

Slide 25 text

E2E(End to End) test の今までとこれから E2Eテストのハードル テスト作成コストの高さ メンテナンスコストも高い 非エンジニアにとってのハードル Maestro, MagicPod のような、テストのメンテナンスコストを比較的小さく抑えられる フレームワークの台頭 非エンジニアでも作成可能 従来のE2Eテストフレームワークに比べ、テストのメンテナンスが容易 E2Eフレームワーク導入によるコストと、E2Eテストを用意しなかったときの人件 費(テスターなど)を考えてみると、割に合うケースが増えてきているかも

Slide 26

Slide 26 text

UI testing framework 'Maestro' Android/iOS/Flutter/ReactNative をサポート yaml でテストフローを定義(Maestro では Flow と呼称) Flow から Flow の呼び出しが可能 ローカル実行可能、CIツール連携も可能(Maestro Cloud) iOS実機で動作しない(シミュレータのみ。 Flutterでは Semantics による wrap か、 scemanticLabel の設定が必要 Semantics( label: "My Label", child: SomeView() ) Maestro by mobile.dev > PLATFORM SUPPORT > Flutter - https://maestro.mobile.dev/platform-support/flutter

Slide 27

Slide 27 text

試してみましょう シナリオ:Android の連絡帳アプリを起動し、新しい連絡先を登録してみる appId: com.android.contacts --- - launchApp - tapOn: "Create new contact" - tapOn: "First name" - inputRandomPersonName - tapOn: "Last name" - inputRandomPersonName - tapOn: "Phone" - inputRandomNumber: length: 10 - back - tapOn: "Email" - inputRandomEmail - tapOn: "Save"

Slide 28

Slide 28 text

(サンプル動画)

Slide 29

Slide 29 text

まとめ コードの品質を高く保ち、ユーザーの信頼を維持するため、テストは非常に重要 テストを書けばいいというわけではなく、テスト種別ごとのスコープと特性を考 える 過大なテストは不要だし、テストを書くことが目的ではない 過去、限定的なケースでしか用途の無かったテスト(E2Eなど)についても、UI テストフレームワークの台頭により簡便化が進み、選択の俎上に プログラミングにおけるテストの歴史はFlutterより古い…沼が深い…

Slide 30

Slide 30 text

(Flutterテスト)(の)沼に(みなさんが)ハマって (くれるよう発表)やってみた 沼っていきましょう

Slide 31

Slide 31 text

ご清聴ありがとうございました