「役に立たない! Flutter の統合テストではエンドツーエンドのテストを実行できない」と、約 9 か月前、当社の顧客の 1 人が叫びました。何が問題なのか尋ねると、ログインには Google 認証を使用し、 パッケージを使用していましたが、Flutter の統合テストを使用してログイン画面を操作することはできなかったと説明されました。私はまだ問題が何なのかをよく理解していませんでしたが、ピンと来ました。このプラグインは、統合テストでは機能しない を使用しています。 google_sign_in ネイティブ UI コンポーネント 当時は解決策を提示できず、放置しなければならなかったことが非常に残念でした。しかし、今日に早送りすると、 と呼ばれる素晴らしい新しいソリューションが発表されました。 。これからすべてを説明しますが、本題に入る前に、テストを実行することがなぜ重要なのか、これまでにどのようなツールが利用できたのかを簡単にまとめてから、Patrol を始める方法について話しましょう。 「パトロール」 リーンコード そもそも、なぜ Flutter アプリをテストするのでしょうか? 開発チームが次のような (CI) サービスを使用する主な理由の 1 つは、 リポジトリにコミットしているコードに関するフィードバックをすぐに得ることです。テストはパイプラインの一部として自動的に実行され、バグや問題を早期に発見してすぐに修正できるため、品質と安定性の両方のレベルを保証できます。私たちは常に、ワークフローを設定するときにテストを実装することをお客様に推奨していますが、「テストを作成する時間がない」という声を聞くことは珍しいことではありません。あなたがそのような状況に陥っておらず、アプリ開発サイクルの一部としてテストを使用して、高品質でバグのないアプリを提供できることを願っています。 継続的インテグレーション コードマジック Flutter アプリをテストする主な自動化方法は何ですか? CI ワークフローの一部として自動化できる主なテスト方法は 4 つあります。テスト自体が重要なトピックなので、簡単に説明しますが、これらのテスト方法を組み合わせて使用すると、アプリの品質を向上させ、問題を早期に発見するのに役立ちます。 まず、 があります。これは、関数とメソッドを個別にテストして、期待どおりに動作することを確認するために一般的に使用されます。単体テストを作成して、ビジネス ロジックがさまざまなシナリオで予期しない結果が発生することなく動作することを確認することもできます。 「単体テスト」 次に、Flutter の を使用すると、UI コンポーネントをテストし、正しくレンダリングされ、期待どおりに動作することを確認できます。 「ウィジェット テスト」 次に、アプリケーションのユニットとコンポーネントが期待どおりに連携して動作するかどうかをテストする があります。 「統合テスト」 最後に、実際のユーザーが使用しているかのようにアプリケーションをテストする があります。 CI ワークフローでは、これは通常、シミュレーターまたはエミュレーターを使用して自動化され、アプリのさまざまな経路をテストし、コードに変更を加えた後に問題がないことを確認します。 「エンドツーエンド UI テスト」 ここで、私が冒頭で話した顧客は、アプリにログインできないためにエンドツーエンドの UI テストを実行できずに行き詰っていました。当時、彼らはログイン部分をバイパスした「開発」バージョンをテストしていました。 しかし、 利用できるようになったため、その必要はなくなりました。 「パトロール」が 入場してステージ左、パトロール! ではまずパトロールとは何でしょうか?まあ、ドキュメントが最もよく言っていると思います: Patrol は、LeanCode によって開発された Flutter 用の新しいオープンソース UI テスト フレームワークです。 Flutter の既存のテスト ツールの上に構築されており、以前は不可能だったことが可能になります。パトロールを使用すると、Flutter アプリが実行されているプラットフォームのネイティブ機能にアクセスできます。 ここで最も重要な部分は、 アプリが実行されているプラットフォームの にアクセスできることです。 Flutter ネイティブ機能 これは、次のようなことができるようになることを意味します。 許可リクエストダイアログを操作して、リクエストを却下または受け入れます。 WebView と対話します。 アプリを最小化および最大化します。 Google 認証や Apple 認証などの認証フローと対話します。 通知トレイを開く、ホームボタンを押す、Wi-Fi 接続のオン/オフ、デバイスのダーク モードへの変更など、他のネイティブ機能と対話します。 なるほど、これは素晴らしいと思いますが、問題は何でしょうか? まあ、それはありません!さらに、 あるだけでなく、 ! 無料で オープンソース さらに、Patrol には、テストを作成するためのより簡潔な構文を提供する も導入されています。それらについて詳しく読むことができます 。 「カスタム ファインダー」 ここ Patrol のインストールと設定 Patrol を開始するには、CLI をインストールし、 に を追加し、iOS および Android プロジェクトでいくつかの構成をセットアップする必要があります。 Pubspec.yaml Patrol 依存関係 いくつかの優れたドキュメントを作成しました ここで各プラットフォームのプロセスを確認できます。ステップバイステップのガイドでは、 と の両方のセットアップについて説明します。 LeanCode は ここ iOS Android 何か問題が発生した場合は、参加できる サーバーに助けを求めるのが最適です。 。 パトロール コミュニティ Discord ここ バグを見つけた場合は問題を提起できます 。 ここ Patrol のインストールと設定 Patrol を開始するには、CLI をインストールし、 に を追加し、iOS および Android プロジェクトでいくつかの構成をセットアップする必要があります。 Pubspec.yaml Patrol 依存関係 いくつかの優れたドキュメントを作成しました ここで各プラットフォームのプロセスを確認できます。ステップバイステップのガイドでは、 と の両方のセットアップについて説明します。 LeanCode は ここ iOS Android 何か問題が発生した場合は、参加できる サーバーに助けを求めるのが最適です。 。 パトロール コミュニティ Discord ここ バグを見つけた場合は問題を提起できます 。 ここ Patrol を使用してネイティブ機能テストを作成する これですべてのセットアップが完了したので、いくつかのネイティブ機能のテストを開始しましょう。自分で試すために、クリックすると アラート ダイアログが開く、高いボタンを備えたシンプルな Flutter アプリをセットアップしました。 ネイティブの 「OK」または「キャンセル」をクリックすると、ダイアログが閉じます。 繰り返しますが、Patrol 独自のドキュメントを使用することをお勧めします。 最初のテスト ファイルを追加します。 ここ そこで、テストとして、「Click me!」というテキストが表示された上部のボタンをクリックしてみました。これは標準の Flutter ウィジェットなので、次のパトロール ファインダーを使用してタップできます。 await $('Click me!').tap(); ネイティブ ダイアログが表示されるので、ネイティブ UI コンポーネントとの対話を開始できるようになります。そこで、「OK」ボタンをタップできるようにするネイティブ ファインダーを追加しましょう。 await $('Click me!').tap(); await $.native.tap(Selector(text: 'OK')); それは簡単でした! 「キャンセル」ボタンもテストしたいので、「クリックしてください!」ボタンをタップしてみましょう。ボタンを再度クリックし、次のようにさらに数行を追加して、ネイティブ ダイアログの [キャンセル] ボタンをタップします。 await $('Click me!').tap(); await $.native.tap(Selector(text: 'OK')); await $('Click me!').tap(); await $.native.tap(Selector(text: 'Cancel')); 完成したテスト ファイルは次のようになります。 import 'package:cmpatrol/main.dart'; import 'package:patrol/patrol.dart'; void main() { patrolTest( 'Native tests', nativeAutomation: true, ($) async { await $.pumpWidgetAndSettle(const MyApp()); await $('Click me!').tap(); await $.native.tap(Selector(text: 'OK')); await $('Click me!').tap(); await $.native.tap(Selector(text: 'Cancel')); await $('Click me!').tap(); await $.native.tap(Selector(text: 'NO')); }, ); } これで、テストを起動するコマンドを使用して、エミュレータまたは実際のデバイスでそのテストを実行できるようになります。私の統合テスト ファイルは という名前だったので、次のようにターミナルからテストを開始しました。 「button_test」 patrol test -t integration_test/button_test.dart テストが成功したか失敗したかをターミナルで直接確認できます。テストが失敗した場合は、完全なテスト レポートへのリンクが表示されます。あるいは、私のように Android でテストを実行している場合は、次のディレクトリの をクリックしてレポートにアクセスできます。 index.html ./build/app/reports/androidTest/connected 通知トレイを開く、Wi-Fi を無効にする、ダーク モードを有効にする、アプリの最小化と最大化など、他のネイティブ機能をさらに試すことができます。 // minimize app await $.native.pressHome(); await $.native.openNotifications(); await $.native.disableWifi(); await $.native.enableDarkMode(); // maximize app await $.native.openApp(); ⚠️ アプリを完全に閉じてから再度開くことはできないことに注意してください。そうするとテスト全体が終了し、テストが失敗するためです。 パトロールに相談してください 他の例については。 ドキュメンテーション Codemagic ワークフローでの Patrol の使用 Patrol をワークフローに組み込むには、まずビルド マシンに をインストールする必要があります。これには数秒しかかかりません。それが完了すると、テスト スクリプトを実行できます。以下は、これらの手順を 構成ファイルの「scripts」セクションに追加する方法の例です。最初のスクリプト ステップの 1 つとして、Patrol CLI をインストールするスクリプトを実行することをお勧めします。その後、その直後、または事前に実行したい他のテストの後に、Patrol テストを実行できます。 Patrol CLI codemagic.yaml パトロール テストを実行する前にエミュレータを起動する必要があるため、エミュレータを起動するスクリプトを追加し、エミュレータが完全に起動するまで待ちます。 Apple Virtualization Framework はネストされた仮想化をサポートしていないため、Apple Silicon M1 または M2 マシンを使用するマシンでは Android エミュレータを利用できないことに注意してください。したがって、Android アプリをテストするときは、 インスタンスを使用することをお勧めします。 Linux の script セクションは次のようになります。 codemagic.yaml scripts: ... - name: Install Patrol CLI script: dart pub global activate patrol_cli - name: Launch Android emulator script: | cd $ANDROID_HOME/tools emulator -avd emulator & adb wait-for-device - name: Run tests with Patrol script: patrol test -t integration_test/your_test.dart ignore_failure: true ... Codemagic ビルド ログに Patrol テスト結果を表示する Patrol テストの結果は 形式でも入手できます。つまり、Codemagic ビルド概要画面のビルド ログに表示できます。生成される JUnit XML ファイルへのパスに プロパティ パスを追加するだけです。ブール値を指定して プロパティを使用すると、ワークフローの残りの部分を実行し続けるかどうかを制御できます。次のセクションで説明するように結果をテスト管理システムにアップロードする場合は、これを に設定する必要があります。 JUnit XML test_report ignore_failure true スクリプトがどのようになるかの例を次に示します。 scripts: ... - name: Run tests with Patrol script: | patrol test -t integration_test/your_test.dart test_report: build/app/outputs/androidTest-results/connected/*.xml ignore_failure: true ... 失敗したテストは次のようになります。 Patrol テスト レポートをビルド アーティファクトとして収集する さらに実行したいことの 1 つは、エラーが発生した場合に完全なレポートを表示できるように、テスト レポート出力をビルド アーティファクトとして収集することです。これを行うと、左側の「アーティファクト」セクションのビルド概要画面でレポートを zip ファイルとしてダウンロードできるようになります。これを行う最も簡単な方法は、レポート ファイルが存在するディレクトリを、Codemagic がアーティファクトのエクスポートに使用するディレクトリにコピーすることです。このディレクトリを参照する という組み込み環境変数があり、スクリプトで使用できます。 $CM_EXPORT_DIR これを行うスクリプトは次のようになります。 scripts: ... - name: Export Patrol test report script: | cp -r build/app/reports/androidTests/connected $CM_EXPORT_DIR/report ... 結論 ネイティブ機能を伴う UI および統合テストの実行の問題をついに克服しました。ネイティブ機能をテストし、認証フローやネイティブ ダイアログを操作したり、Wi-Fi、セルラー、ダーク モードなどのネイティブ機能を切り替えたり、アプリの最小化と最大化を行うこともできるようになりました。さらに、これは かつ 、Flutter の発売以来存在している実際の問題に対する解決策を提供します。さらに、Codemagic ワークフローに簡単に追加して使用できます。 LeanCode の素晴らしい取り組みをサポートしたい場合は、pub.dev で Patrol に「いいね!」を押してください。 Patrol GitHub リポジトリにスターを付けます 。 Patrol は、 無料 オープンソースであり ここ ここ この記事は、次のソリューション エンジニアリング責任者である Kevin Suhajda によって書かれています。 。ケビンは次のサイトで見つけることができます 、 、 そして 。 コードマジック バツ GitHub リンクトイン でも公開されています。 ここ