「役に立たない! Flutter の統合テストではエンドツーエンドのテストを実行できない」と、約 9 か月前、当社の顧客の 1 人が叫びました。何が問題なのか尋ねると、ログインには Google 認証を使用し、 google_sign_inパッケージを使用していましたが、Flutter の統合テストを使用してログイン画面を操作することはできなかったと説明されました。私はまだ問題が何なのかをよく理解していませんでしたが、ピンと来ました。このプラグインは、統合テストでは機能しないネイティブ UI コンポーネントを使用しています。
当時は解決策を提示できず、放置しなければならなかったことが非常に残念でした。しかし、今日に早送りすると、 「パトロール」と呼ばれる素晴らしい新しいソリューションが発表されました。
開発チームが次のような継続的インテグレーション(CI) サービスを使用する主な理由の 1 つは、
CI ワークフローの一部として自動化できる主なテスト方法は 4 つあります。テスト自体が重要なトピックなので、簡単に説明しますが、これらのテスト方法を組み合わせて使用すると、アプリの品質を向上させ、問題を早期に発見するのに役立ちます。
まず、 「単体テスト」があります。これは、関数とメソッドを個別にテストして、期待どおりに動作することを確認するために一般的に使用されます。単体テストを作成して、ビジネス ロジックがさまざまなシナリオで予期しない結果が発生することなく動作することを確認することもできます。
次に、Flutter の「ウィジェット テスト」を使用すると、UI コンポーネントをテストし、正しくレンダリングされ、期待どおりに動作することを確認できます。
次に、アプリケーションのユニットとコンポーネントが期待どおりに連携して動作するかどうかをテストする「統合テスト」があります。
最後に、実際のユーザーが使用しているかのようにアプリケーションをテストする「エンドツーエンド UI テスト」があります。 CI ワークフローでは、これは通常、シミュレーターまたはエミュレーターを使用して自動化され、アプリのさまざまな経路をテストし、コードに変更を加えた後に問題がないことを確認します。
ここで、私が冒頭で話した顧客は、アプリにログインできないためにエンドツーエンドの UI テストを実行できずに行き詰っていました。当時、彼らはログイン部分をバイパスした「開発」バージョンをテストしていました。
しかし、 「パトロール」が利用できるようになったため、その必要はなくなりました。
ではまずパトロールとは何でしょうか?まあ、ドキュメントが最もよく言っていると思います:
Patrol は、LeanCode によって開発された Flutter 用の新しいオープンソース UI テスト フレームワークです。 Flutter の既存のテスト ツールの上に構築されており、以前は不可能だったことが可能になります。パトロールを使用すると、Flutter アプリが実行されているプラットフォームのネイティブ機能にアクセスできます。
ここで最も重要な部分は、 Flutterアプリが実行されているプラットフォームのネイティブ機能にアクセスできることです。
これは、次のようなことができるようになることを意味します。
なるほど、これは素晴らしいと思いますが、問題は何でしょうか?
まあ、それはありません!さらに、無料であるだけでなく、
さらに、Patrol には、テストを作成するためのより簡潔な構文を提供する「カスタム ファインダー」も導入されています。それらについて詳しく読むことができます
Patrol を開始するには、CLI をインストールし、 Pubspec.yamlにPatrol 依存関係を追加し、iOS および Android プロジェクトでいくつかの構成をセットアップする必要があります。
LeanCode はいくつかの優れたドキュメントを作成しました
何か問題が発生した場合は、参加できるパトロール コミュニティ Discordサーバーに助けを求めるのが最適です。
バグを見つけた場合は問題を提起できます
Patrol を開始するには、CLI をインストールし、 Pubspec.yamlにPatrol 依存関係を追加し、iOS および Android プロジェクトでいくつかの構成をセットアップする必要があります。
LeanCode はいくつかの優れたドキュメントを作成しました
何か問題が発生した場合は、参加できるパトロール コミュニティ Discordサーバーに助けを求めるのが最適です。
バグを見つけた場合は問題を提起できます
これですべてのセットアップが完了したので、いくつかのネイティブ機能のテストを開始しましょう。自分で試すために、クリックするとネイティブのアラート ダイアログが開く、高いボタンを備えたシンプルな 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();
⚠️ アプリを完全に閉じてから再度開くことはできないことに注意してください。そうするとテスト全体が終了し、テストが失敗するためです。
パトロールに相談してください
Patrol をワークフローに組み込むには、まずビルド マシンにPatrol CLIをインストールする必要があります。これには数秒しかかかりません。それが完了すると、テスト スクリプトを実行できます。以下は、これらの手順をcodemagic.yaml構成ファイルの「scripts」セクションに追加する方法の例です。最初のスクリプト ステップの 1 つとして、Patrol CLI をインストールするスクリプトを実行することをお勧めします。その後、その直後、または事前に実行したい他のテストの後に、Patrol テストを実行できます。
パトロール テストを実行する前にエミュレータを起動する必要があるため、エミュレータを起動するスクリプトを追加し、エミュレータが完全に起動するまで待ちます。 Apple Virtualization Framework はネストされた仮想化をサポートしていないため、Apple Silicon M1 または M2 マシンを使用するマシンでは Android エミュレータを利用できないことに注意してください。したがって、Android アプリをテストするときは、 Linuxインスタンスを使用することをお勧めします。
codemagic.yamlの script セクションは次のようになります。
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 ...
Patrol テストの結果はJUnit XML形式でも入手できます。つまり、Codemagic ビルド概要画面のビルド ログに表示できます。生成される 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 ...
失敗したテストは次のようになります。
さらに実行したいことの 1 つは、エラーが発生した場合に完全なレポートを表示できるように、テスト レポート出力をビルド アーティファクトとして収集することです。これを行うと、左側の「アーティファクト」セクションのビルド概要画面でレポートを zip ファイルとしてダウンロードできるようになります。これを行う最も簡単な方法は、レポート ファイルが存在するディレクトリを、Codemagic がアーティファクトのエクスポートに使用するディレクトリにコピーすることです。このディレクトリを参照する$CM_EXPORT_DIRという組み込み環境変数があり、スクリプトで使用できます。
これを行うスクリプトは次のようになります。
scripts: ... - name: Export Patrol test report script: | cp -r build/app/reports/androidTests/connected $CM_EXPORT_DIR/report ...
Patrol は、ネイティブ機能を伴う UI および統合テストの実行の問題をついに克服しました。ネイティブ機能をテストし、認証フローやネイティブ ダイアログを操作したり、Wi-Fi、セルラー、ダーク モードなどのネイティブ機能を切り替えたり、アプリの最小化と最大化を行うこともできるようになりました。さらに、これは無料かつオープンソースであり、Flutter の発売以来存在している実際の問題に対する解決策を提供します。さらに、Codemagic ワークフローに簡単に追加して使用できます。 LeanCode の素晴らしい取り組みをサポートしたい場合は、pub.dev で Patrol に「いいね!」を押してください。
この記事は、次のソリューション エンジニアリング責任者である Kevin Suhajda によって書かれています。
ここでも公開されています。